Доступ к ресурсам WPF XAML из не-WPF кода - PullRequest
7 голосов
/ 04 марта 2009

В настоящее время я создаю приложение, состоящее из нескольких компонентов, каждый из которых по сути является пользовательским элементом управления WPF с небольшим кодом C # для работы системы плагинов (с использованием MEF).

Проблема, с которой я сталкиваюсь, состоит в том, что каждый компонент должен содержать значок, и для удобства я определил это как System.Windows.Media.Brush, поэтому я могу просто использовать DrawingBrush, экспортированный из Design. Теперь мне нужно получить доступ к этому куску XAML из C # не-WPF, где у меня сейчас ужасный обходной путь создания пользовательского элемента управления и запроса его ресурса:

private Brush CachedIcon = null;

public override Brush Icon
{
    get
    {
        if (CachedIcon == null)
        {
            CachedIcon = (Brush)(new BlahControl().TryFindResource("Icon"));
        }
        return CachedIcon;
    }
}

Я не смог найти способ прочитать этот ресурс (который является файлом .xaml и на который есть ссылка в ResourceDictionary в пользовательском элементе управления) из "обычного" класса C #. У всего, что принадлежит WPF, есть такой замечательный метод TryFindResource, но как это сделать иначе? Я не хочу, чтобы файл XAML со значком лежал без встраивания.

Ответы [ 4 ]

2 голосов
/ 10 марта 2009

В своем коде XAML убедитесь, что для ресурса значка установлен параметр сборки «Ресурс», а затем обратитесь к ресурсу, чтобы сделать его статическим ресурсом xaml

<UserControl.Resources>
    <BitmapImage x:Key="icon1" UriSource="Resources/Icon1.ico" />
</UserControl.Resources>

Тогда в вашем коде .Net 2.0 вы найдете ресурс в потоке "{xamlName} .g.resource"

Пример кода, который загружает все иконки из dll xaml в словарь:

using System.IO;
using System.Reflection;
using System.Collections;
using System.Resources;

...

var icons = new Dictionary<String, Bitmap>();
var externalBaml = Assembly.LoadFile(Path.Combine(Environment.CurrentDirectory, "MyXaml.dll"));
Stream resourceStream = externalBaml.GetManifestResourceStream(externalBaml.GetName().Name + ".g.resources");
using (ResourceReader resourceReader = new ResourceReader(resourceStream)) {
    foreach (DictionaryEntry resourceEntry in resourceReader) {
        if (resourceEntry.Key.ToString().ToUpper().EndsWith(".ICO")) {
            icons.Add(resourceEntry.Key.ToString(), Image.FromStream(resourceEntry.Value as Stream) as Bitmap);
        }
    }
}
1 голос
/ 12 марта 2009

Мои предложения:

  • Предоставьте метаданные для вашего элемента управления о том, где можно найти значок. Вы можете сделать это с вашим собственным атрибутом (см. Пример 1 ниже). Эти метаданные позволят вам загрузить значок, не создавая экземпляр элемента управления.

  • Поскольку вы используете MEF, вы можете использовать метаданные в своем экспорте для достижения того же, что и выше. Подробности здесь . См. Пример 2 ниже.

  • Относитесь к вашей иконке как ImageSource, а не Brush. Вы можете использовать Image элемент управления WPF, чтобы показать свой ImageSource, или вы можете нарисовать его ImageBrush.

  • Используйте технику, предоставленную TFD, для чтения ресурса с именем, указанным в метаданных. К сожалению, WPF, по-видимому, не предоставляет ничего похожего на BamlReader, что сделает загрузку ресурса WPF из контекста, не относящегося к WPF, намного чище.

Пример 1:

[Icon("MyIconResourceName")]
public class BlahControl : Control
{
    ...
}

Пример 2:

[Export(typeof(IApplicationComponent))]
[ExportMetadata("IconResource", "MyIconResourceName")]
public class BlahControl : Control
{
    ...
}
0 голосов
/ 08 марта 2009

Определите значки на уровне приложения, а не в элементе управления, либо в файле app.xaml, либо в файле xaml словаря основных ресурсов. Затем вы можете использовать тот же метод TryFindResource, но без создания экземпляра элемента управления.

0 голосов
/ 04 марта 2009

Вы можете читать ресурсы из вашей сборки как поток.

Пример кода здесь: http://www.wpftutorial.net/ReadWPFResourcesFromWinForms.html

...