XamlReader с изображениями

Я создаю приложение в WPF (.Net 3.5), которое я хочу иметь возможность настраивать для каждого клиента. Я абстрагировал ресурсы для внешних файлов xaml (theme). С файлом xaml, созданным как Page, это работает отлично.

Теперь я хочу использовать XamlReader динамически загружать файлы xaml темы. Таким образом, я могу скомпилировать приложение, а другие могут настроить приложение (для каждого клиента) без необходимости повторной компиляции или доступа к исходному коду. Вот снимок того, что я делаю:

Directory.GetFiles(pathToThemeDirectory).Each((file) =>
{
     using (Stream stream = new FileStream(file, FileMode.Open))
     {
          var dir = Directory.GetCurrentDirectory();
          var dict = XamlReader.Load(stream) as ResourceDictionary;
          Application.Current.Resources.MergedDictionaries.Add(dict);
     }
});

Теперь, кажется, правильно разобрать Xaml. Однако теперь я получаю сообщение об ошибке, которое выглядит следующим образом:

Cannot convert string '/Path/To/Image/File.ico' in attribute 'Icon' to object of 
type 'System.Windows.Media.ImageSource'. Cannot locate resource
'/Path/To/Image/File.ico'.  Error at object 'System.Windows.Setter'

Я хочу иметь возможность изменять эти ресурсы для каждого клиента (изображения логотипа и т. Д.), Поэтому я изменил действие по сборке с Resource в None и сказал всегда копировать в выходной каталог.

Есть ли какие-либо предложения о том, как проанализировать Xaml во время выполнения и изменить мою конфигурацию, чтобы получить ресурсы изображений, которые не нужно компилировать в сборке? Или я совершенно не в своей тарелке и есть способ лучше настроить эту тему?


Обновить:

Вот точная строка, которая дает ошибку:

<Style x:Key="MainWindow">
    <Setter Property="Window.Icon" Value="/Assets/icon.ico" />
</Style>

Но это потому, что это первый загруженный актив. Вот еще один пример:

<ImageBrush x:Key="NavigationBackgroundImage" ImageSource="Assets/bg.png" TileMode="Tile" Stretch="UniformToFill"/>

Они просто используются в стилях, доступ к которым осуществляется через:

{StaticResource MainWindow}

или же

{StaticResource NavigationBackgroundImage}

1 ответ

Решение

Похоже, вам нужно создать ParserContext в соответствии с этим блогом.

В этом примере он делал:

var resourceDictionary = XamlReader.Load(fileStream) as ResourceDictionary;
if(resourceDictionary != null)
{
    Resources.MergedDictionaries.Add(resourceDictionary)
}

Но впоследствии код был изменен на:

var applicationDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
if(!String.IsNullOrEmpty(applicationDirectory ))
{

    var runtimeResourcesDirectory = Path.Combine(applicationDirectory , "RuntimeResources");
    var pc = new ParserContext
    {
        BaseUri = new Uri(runtimeResourcesDirectory , UriKind.Absolute)
    };
    if(Directory.Exists(runtimeResourcesDirectory ))
    {
        foreach (string resourceDictionaryFile in Directory.GetFiles(runtimeResourcesDirectory , "*.xaml"))
        {
            using (Stream s = File.Open(resourceDictionaryFile, FileMode.Open, FileAccess.Read))
            {
                try
                {
                    var resourceDictionary = XamlReader.Load(s, pc) as ResourceDictionary;
                    if (resourceDictionary != null)
                    {
                        Resources.MergedDictionaries.Add(resourceDictionary);
                    }
                }
                catch
                {
                    MessageBox.Show("Invalid xaml: " + resourceDictionaryFile);
                }
            }
        }
    }
}

Надеюсь это поможет!

Другие вопросы по тегам