С# - загрузка изображения из другой сборки

У меня есть образ в другой сборке:

  • (.NET Standard 1.4) ResourcesAssembly/Common/Images/CompanyLogo.png - обязательное требование
  • Build Action: Content - обязательное требование
  • Копировать в выходной каталог: Копировать, если новее (я проверял после компиляции - требуемое изображение представлено в выходном каталоге, где находится мой exe - например, Debug/Common/Images/CompanyLogo.png. Так что не должно быть проблем с получением это оттуда.)

Я хочу вставить его в сборку моего приложения (WPF) внутри окна. Пробую 2 варианта.

1.

<Image Source="pack://siteoforigin:,,,/Common/Images/CompanyLogo.png" />

Изображение в интерфейсе видно во время выполнения. Но дизайнер VS XAML не показывает изображение во время разработки и говорит, что это ошибка:

Не удалось найти часть пути «C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE\Common\Images\CompanyLogo.png».

2.

<Image Source="pack://application:,,,/ResourcesAssembly;component/Common/Images/CompanyLogo.png" />

Изображение не отображается во время выполнения, но во время разработки все в порядке.

Visual Studio 2017 Community Edition 15.4.4.

Так что первый вариант мне кажется подходящим, но эта странная ошибка - почему он пытается найти изображение в папке Visual Studio? Параметр «siteoforigin» относится к исполняемому файлу приложения, а не к исполняемому файлу Visual Studio, не так ли?

ОБНОВЛЕНИЕ

Пробовал второй вариант с действием сборки как «Встроенный ресурс» (ResourcesAssembly — это проект .NET Standard 1.4). Даже почистил и пересобрал раствор. Результат такой же, как и во втором варианте: изображение не видно во время выполнения, но во время проектирования оно видно.


person Alex34758    schedule 11.02.2018    source источник
comment
Действие сборки должно быть Ресурс, а не Встроенный ресурс.   -  person Clemens    schedule 12.02.2018
comment
В типе проекта .NET Standard 1.4 нет параметра Resource. Единственный встроенный ресурс, который я считаю ресурсом в обычных типах проектов .NET. разве я не права?   -  person Alex34758    schedule 12.02.2018
comment
Нет, ты не прав. Ресурс отличается от Встроенного ресурса (по крайней мере, в проекте WPF). Не знаю, можете ли вы вообще иметь ресурс сборки в проекте .NET Standard (т.е. тот, который разрешается с помощью URI пакета ресурсов).   -  person Clemens    schedule 12.02.2018
comment
Я читал, что ресурс предназначен только для WPF, поэтому встроенный ресурс должен подходить как для WPF, так и для .NET Standard. Не так ли?   -  person Alex34758    schedule 12.02.2018
comment
Нет, я так не думаю. URI пакета файлов ресурсов не разрешает встроенный ресурс.   -  person Clemens    schedule 12.02.2018
comment
Поэтому кажется, что единственный способ для меня - использовать первый вариант и не обращать внимания на то, что дизайнер XAML не показывает изображение.   -  person Alex34758    schedule 12.02.2018


Ответы (2)


Параметр «siteoforigin» относится к исполняемому файлу приложения, а не к исполняемому файлу Visual Studio, не так ли?

Точно, siteoforigin указывает на исполняемый каталог сборки. Но когда вы используете конструктор XAML VS, сборка выполняется ... XDesProc.exe из указанного вами каталога (C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\Common7\IDE). Вот почему путь поиска изображений ...\IDE\Common\Images\CompanyLogo.png.

Вы можете спросить: «Есть ли способ правильно отобразить изображение как в WPF Designer, так и во время выполнения приложения?» Что ж, если вы хотите сохранить оба требования (1-е — изображение во внешней сборке ресурсов, 2-е — действие сборки для изображения, установленное на «Содержимое»), то, вероятно, нет. По крайней мере, я не могу найти решение.

Вариант с правами доступа siteorigin в пакетном URI не подходит, т. к. образ должен загружаться в разных приложениях с разным исполняемым каталогом (см. выше).

Вариант с правами доступа application в URI пакета не подходит, поскольку он работает только для файлов ресурсов, скомпилированных в сборку (локальную или по ссылке). На самом деле это причина, по которой вы не видите изображение во время выполнения с вашим вторым вариантом.

Так что если 1-й вариант вас устраивает, то ок, это лучшее, что вы могли иметь, не нарушая заявленных вами требований. Ближайшее решение, позволяющее корректно видеть изображение как в Дизайнере, так и во время выполнения, — установить для изображения Build Action значение Resource и использовать 2-й исходный путь с правами доступа application.

ОБНОВЛЕНИЕ

Действие сборки «Ресурс» недоступно для библиотеки классов .Net Standard. Я не нашел никакой информации, будет ли он когда-либо поддерживаться. На данный момент, если ваш ResourcesAssembly должен быть нацелен на .Net Standard, лучше всего использовать первый вариант, который вы описали в вопросе.

person CodeFuller    schedule 11.02.2018
comment
Установка для действия сборки значения Resource сделает файл изображения фактическим ресурсом сборки и лучше всего подходит для вопроса о загрузке изображения из сборки или изображения в [a] другая сборка. - person Clemens; 11.02.2018
comment
@CodeFuller Добавлено обновление в мой вопрос - пытался сделать по вашему совету - все еще не может получить видимое изображение в конструкторе XAML и приложении WPF во время выполнения. Хотя для меня пока больше всего подходит первый вариант, просто интересно в чем проблема. - person Alex34758; 12.02.2018
comment
@Clemens прав в своем комментарии к вашему вопросу, выберите «Ресурс», а не «Встроенный ресурс». - person CodeFuller; 12.02.2018
comment
@CodeFuller В типе проекта .NET Standard 1.4 нет параметра «Ресурс». Единственный встроенный ресурс, который я считаю ресурсом в обычных типах проектов .NET. разве я не права? - person Alex34758; 12.02.2018
comment
Я уточнил свой вопрос, что библиотека ресурсов относится к типу .NET Standard 1.4. - person Alex34758; 12.02.2018
comment
Я полностью понял ответ из вашего объяснения @CodeFuller. Я топнул. Но когда вы используете конструктор XAML VS, выполнение сборки ... XDesProc.exe, где я часто завершаю этот процесс, когда свойства моего конструктора перестают реагировать на мой щелчок или ввод. Теперь я понимаю о siteoforigin - person Luiey; 18.07.2018

Я новичок в WPF, и совсем недавно в свободное время, работая над хобби-проектом, я столкнулся с очень похожей проблемой с аналогичными ограничениями.

Тем не менее, как вы уже поняли, application отлично работает во время разработки, но не во время выполнения, а siteoforigin — наоборот. Таким образом, один из логических способов решить эту проблему — просто использовать оба варианта: siteoforigin во время выполнения и application во время разработки.

Для этого вам нужно будет просто перехватить настройку свойства Source вашего элемента управления. Один из способов сделать это — использовать наследование.


Ниже приведен пример, который делает это для ResourceDictionary:

Реализация

/// <summary>
/// A modified type of <see cref="ResourceDictionary"/> that translates "Resource" pack URIs to "Site of Origin"
/// pack URIs when in runtime.
///
/// i.e. This allows you to declare pack URIs as "pack://application:,,,", which will be resolved
/// as such in design mode while at runtime, actually using "pack://siteoforigin:,,,".
/// </summary>
public class SiteOfOriginResourceDictionary : ResourceDictionary
{
    private const string SiteOfOriginPrefix = "pack://siteoforigin:,,,";
    private const string ApplicationPrefix = "pack://application:,,,";

    private const string UseRedirectSource = "Please use RedirectSource instead of Source";
    private string _originalUri;

    /// <summary>
    /// Gets or sets the design time source.
    /// </summary>
    public string RedirectSource
    {
        get => _originalUri;

        set
        {
            this._originalUri = value;
            bool isInDesignMode = (bool) DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue;

            if (! isInDesignMode)
            {
                if (value.Contains(ApplicationPrefix))
                    value = value.Replace(ApplicationPrefix, SiteOfOriginPrefix);
            }

            base.Source = new Uri(value);
        }
    }

    /// <summary>
    /// Please use <see cref="RedirectSource"/> instead.
    /// </summary>
    public new Uri Source
    {
        get => throw new Exception(UseRedirectSource);
        set => throw new Exception(UseRedirectSource);
    }
}

Пример использования

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <SiteOfOriginResourceDictionary RedirectSource="pack://application:,,,/Theme/Default/Root.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</ResourceDictionary.MergedDictionaries>

На практике это решение сработало для меня, и я активно использую этот код. Я совершенно уверен, что вы можете сделать то же самое с Image и/или другими компонентами WPF.

Тем не менее, в моем случае мне нужно было поддерживать это только на ResourceDictionary. Это решение было бы неоптимальным в вашем случае, поскольку вам, вероятно, (в конечном итоге) потребуется сделать это для нескольких элементов управления в будущем.

Таким образом, я бы предложил в качестве потенциального решения дальнейшее исследование использования Attached Properties, создание присоединенного свойства, которое устанавливает Source элемента управления, переключение между application во время разработки и siteoforigin во время выполнения.

Вместо этого это можно было бы повторно использовать для нескольких элементов управления без необходимости наследовать каждый раз для каждого нового элемента управления/класса.


В связи с этим я не могу сказать, что знаю, почему использование application работает в конструкторе, когда действие сборки для ресурса установлено на Content. Согласно документации этот URI должен использоваться, когда ресурс "компилируется в сборку, на которую ссылаются" (Source), но, тем не менее, это работает для меня.

Это мой первый пост на StackOverflow, и я любитель, поэтому, пожалуйста, будьте со мной полегче ????.

person Sewer56    schedule 18.05.2019