带图像的XamlReader

时间:2012-07-11 14:40:29

标签: c# wpf xaml xamlreader

我正在WPF(.Net 3.5)中创建一个应用程序,我希望能够基于每个客户端进行自定义。我将资源抽象为外部xaml(主题)文件。将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 个答案:

答案 0 :(得分:3)

您似乎需要根据此blog创建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);
                }
            }
        }
    }
}

希望这有帮助!