Silverlight共享合并字典

4

我正在使用 Silverlight 4 并尝试共享一些常见的样式(颜色、画笔)。 我的想法是将它们放入“Common.xaml”资源字典中,然后在所有其他资源字典中使用它。 像这样引用每个内容:

<Application 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  x:Class="SampleApp.App"
>
  <Application.Resources>

    <ResourceDictionary>

      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="Assets/Styles/Common.xaml"/>
        <ResourceDictionary Source="Assets/Styles/TextBoxStyle.xaml"/>
      </ResourceDictionary.MergedDictionaries>

    </ResourceDictionary>

  </Application.Resources>

</Application>

问题是,我在InitializeComponent上遇到了一个异常,指出无法找到常用样式(Cannot find a Resource with the Name/Key....)

我必须在每个资源字典中显式引用“Common.xaml”……这基本上导致了“Common.xaml”中包含的每个颜色、笔刷、模板等都会被多次实例化。

难道没有任何方法可以在Silverlight中共享资源,以便它们只被实例化一次吗?

4个回答

4
问题在于Silverlight似乎可以简化资源字典的加载,以便多个字典可以并行加载。因此,当一个字典依赖于另一个字典时,该依赖关系可能无法及时准备好。
由于ResourceDictionary没有内置手段来描述相互依赖关系,也没有事件来指示何时已加载,我能想到的唯一解决方案是自己管理字典的加载。
以下是您可以添加到App.xaml.cs文件中的函数,以“手动”加载资源字典:
    private void LoadResource(Uri uri)
    {
        var info = Application.GetResourceStream(uri);
        string xaml;
        using (var reader = new StreamReader(info.Stream))
        {
            xaml = reader.ReadToEnd();
        }

        ResourceDictionary result = XamlReader.Load(xaml) as ResourceDictionary;

        if (result != null)
        {
            Resources.MergedDictionaries.Add(result);
        }
    }

现在在Application_Startup中,在分配RootVisual之前,您将使用以下代码:

    LoadResource(new Uri"Assets/Styles/Common.xaml", UriKind.Relative));
    LoadResource(new Uri("Assets/Styles/TextBoxStyle.xaml", UriKind.Relative));

虽然这种方法不如使用Source属性高效,但它可以正常工作。如果您有许多这样的字典,并且只有少量包含共享资源的“常规”字典,则可以使用此技术仅加载“常规”字典,然后使用:

Resource.MergedDictionaries.Add(new ResourceDictionary() {Source = new Uri("Assets/Styles/TextBoxStyle.xaml", UriKind.Relative)});

对于那些彼此之间没有依赖关系的其他字典。

太棒了,谢谢!我不得不更改你的LoadResource调用为:LoadResource(new Uri("ProjectResources;component/Resources/Stylesheets/ComboBox.xaml", UriKind.Relative)); 当我尝试你的示例时,我得到了一个异常,说Uri不受支持。此外,当这个东西存在时,Blend中会失去设计视图。我不是很擅长开发,所以我只是在注释/取消注释app.xaml来设置样式。 - dex3703

1

我成功地调整了http://www.wpftutorial.net/MergedDictionaryPerformance.html提出的解决方案,使其能够在Silverlight和VS设计师中运行(尚未尝试Blend)。我在这里写了一篇博客文章(http://softnotes.wordpress.com/2011/04/05/shared-resourcedictionary-for-silverlight/)。

public class SharedResourceDictionary : ResourceDictionary
{
    public static Dictionary<Uri, ResourceDictionary> _sharedDictionaries =
       new Dictionary<Uri, ResourceDictionary>();

    private Uri _sourceUri;
    public new Uri Source
    {
        get { return _sourceUri; }
        set
        {
            _sourceUri = value;
            if (!_sharedDictionaries.ContainsKey(value))
            {
                Application.LoadComponent(this, value);
                _sharedDictionaries.Add(value, this);
            }
            else
            {
                CopyInto(this, _sharedDictionaries[value]);
            }
        }
    }

    private static void CopyInto(ResourceDictionary copy, ResourceDictionary original)
    {
        foreach (var dictionary in original.MergedDictionaries)
        {
            var mergedCopy = new ResourceDictionary();
            CopyInto(mergedCopy, dictionary);
            copy.MergedDictionaries.Add(mergedCopy);
        }
        foreach (DictionaryEntry pair in original)
        {
            copy.Add(pair.Key, pair.Value);
        }
    }
}

XAML 的使用:

<ResourceDictionary.MergedDictionaries>
    <ui:SharedResourceDictionary Source="/my_assembly_name;component/Resources/Shared.xaml"/>
</ResourceDictionary.MergedDictionaries>

0
另一个这个主题上的有趣观点是,如果同一个样式在两个不同的字典中找到,SL只会保留其中一份副本。最后加载的那个样式胜出。换句话说,如果你有两个不同的样式都有相同的键,当第二个样式加载时,第一个样式会被丢弃掉。

0

如果您在加载时遇到错误,请确保构建操作设置为以下之一:

//In the dll, which is in the xap, marked as Build Action: Resource or Page
LoadResource(new Uri("SilverlightApplication48;component/GlobalAssets.xaml", UriKind.Relative));

//In the xap at the same level as the dll, (not in the dll) marked as Build Action: Content.
LoadResource(new Uri("Dictionary1.xaml", UriKind.Relative));

//In a separate library, marked as Build Action: Resource or Page.
LoadResource(new Uri("StylesLibrary;component/Dictionary2.xaml", UriKind.Relative));

格雷格


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接