【问题标题】:Merging dictionaries into multiple user controls - does this affect memory?将字典合并到多个用户控件中——这会影响内存吗?
【发布时间】:2015-02-14 17:50:05
【问题描述】:

我有一个 UI 项目,其中包含(到目前为止)18 个 XAML 资源,它们像这样合并到 App.xaml 中:-

<Application ...>
   <Application.Resources>
       <ResourceDictionary>
           <ResourceDictionary.MergedDictionaries>
               <ResourceDictionary Source="pack://application:,,,/foo.Client.Common;component/UIStyles/Colours.xaml" />
               <ResourceDictionary Source="pack://application:,,,/foo.Client.Common;component/UIStyles/Buttons.xaml" />
               <ResourceDictionary Source="pack://application:,,,/foo.Client.Common;component/UIStyles/Menus.xaml" />
               // etc..
           </ResourceDictionary.MergedDictionaries>
       </ResourceDictionary>
   </Application.Resources>
</Application>

当我在这个项目中编辑任何 XAML 视图时,我会在这些资源中包含的样式名称上获得智能感知 (Resharper)。

现在,应用程序也实现了“插件”架构,并且有几个包含视图和视图模型的类库项目;这些在运行时动态加载。尽管应用程序运行良好,但在这些项目中编辑 XAML 视图时,我没有获得样式名称智能感知。我可以通过将必要的样式合并到视图的 XAML 中来让智能感知工作,例如:-

<UserControl.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="pack://application:,,,/foo.Client.Common;component/UIStyles/Buttons.xaml" />
            //etc..
        </ResourceDictionary.MergedDictionaries>

        // User control-specific styles go here.
    </ResourceDictionary>
</UserControl.Resources>

通过在每个用户控件中执行此操作,我是否会“复制”每个资源并因此膨胀应用程序的内存需求?如果是这样,有什么办法可以解决吗?如果我在类库中创建了一个资源文件,将 15 个“核心”资源合并到其中,然后将这一个资源合并到我的视图中会怎样?还会导致同样的问题吗?

如果做不到这一点,我想我将不得不在每个视图中注释掉“合并 XAML”,并仅在需要处理视图时临时恢复它。

【问题讨论】:

    标签: wpf xaml


    【解决方案1】:

    好问题。我也有同样的问题。

    这里基本上有两个问题:

    1) Xaml 代码中令人讨厌的重复 - 我不是在谈论实际资源的重复 - 相反,你必须在任何地方写 &lt;ResourceDictionary&gt;

    2) 实际的资源重复——浪费资源,另外:如果样式没有放在同一个地方,你将失去在运行时换出样式的好处。

    你如何解决这些问题?

    通过创建新的 xaml 文件,将其命名为 SharedResourceDictionary.xaml,其中包含所有资源。这将包含在App.xaml 中。

    这基本上允许您将ResourceDictionary 拉到其他xaml 组件中,简而言之,只需包含SharedResourceDictionary.xaml

    第二个技巧是确保资源只被创建一次:

    [assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", 
    "WPFTutorial.Utils")]
    
    /// <summary>
    /// The shared resource dictionary is a specialized resource dictionary
    /// that loads it content only once. If a second instance with the same source
    /// is created, it only merges the resources from the cache.
    /// </summary>
    public class SharedResourceDictionary : ResourceDictionary
    {
        /// <summary>
        /// Internal cache of loaded dictionaries 
        /// </summary>
        public static Dictionary<Uri, ResourceDictionary> _sharedDictionaries =
            new Dictionary<Uri, ResourceDictionary>();
    
        /// <summary>
        /// Local member of the source uri
        /// </summary>
        private Uri _sourceUri;
    
        /// <summary>
        /// Gets or sets the uniform resource identifier (URI) to load resources from.
        /// </summary>
        public new Uri Source
        {
            get { return _sourceUri; }
            set
            {
                _sourceUri = value;
    
                if (!_sharedDictionaries.ContainsKey(value))
                {
                    // If the dictionary is not yet loaded, load it by setting
                    // the source of the base class
                    base.Source = value;
    
                    // add it to the cache
                    _sharedDictionaries.Add(value, this);
                }
                else
                {
                    // If the dictionary is already loaded, get it from the cache
                    MergedDictionaries.Add(_sharedDictionaries[value]);
                }
            }
        }
    }
    

    如果这不起作用,下面有一些 cmets:http://www.wpftutorial.net/MergedDictionaryPerformance.html

    还可以探索xaml ifdef代码的土地:

    Does XAML have a conditional compiler directive for debug mode?

    【讨论】:

    • 标记为已回答,尽管它并没有我预期的那么大。这个解决方案仍然存在设计时问题,尽管它不会破坏交易。有关更多详细信息,请参阅下面我自己的回复。
    【解决方案2】:

    我已将 Chris Eelmaa 的回复标记为答案,但请参阅下面的我的 cmets。如果有人感兴趣,这里是 SharedResourceDictionaryClass 的修改版本,其中包括一些调整以改进设计时支持并使其线程安全,基于 wpftutorial 站点上链接到的 cmets克里斯:-

    public class SharedResourceDictionary : ResourceDictionary
    {
        private static readonly Dictionary<Uri, ResourceDictionary> SharedDictionaries =
            new Dictionary<Uri, ResourceDictionary>();
        private Uri _sourceUri;
    
        /// <summary>
        /// Gets or sets the uniform resource identifier (URI) to load resources from.
        /// </summary>
        public new Uri Source
        {
            get
            {
                return IsInDesignMode ? base.Source : _sourceUri;
            }
            set
            {
                if (IsInDesignMode)
                {
                    try
                    {
                        base.Source = value;
                    }
                    catch
                    {
                    }
                    return;
                } 
    
                _sourceUri = new Uri(value.OriginalString);
    
                if (!SharedDictionaries.ContainsKey(value))
                {
                    base.Source = value;
                    lock (((ICollection)SharedDictionaries).SyncRoot)
                    {
                        SharedDictionaries.Add(value, this);
                    }
                }
                else
                {
                    lock (((ICollection)MergedDictionaries).SyncRoot)
                    {
                        MergedDictionaries.Add(SharedDictionaries[value]);
                    }
                }
            }
        }
    
        /// <summary>
        /// Gets a value indicating whether [is in design mode].
        /// </summary>
        private static bool IsInDesignMode
        {
            get
            {
                return (bool)DependencyPropertyDescriptor.FromProperty(
                    DesignerProperties.IsInDesignModeProperty,
                    typeof(DependencyObject)).Metadata.DefaultValue;
            }
        }
    }
    

    (不知道为什么 SO 不对这段代码着色!)

    然后将 ResourceDictionary 替换为 SharedResourceDictionary(当然还有适当的 XML 命名空间),例如:-

    <ResourceDictionary.MergedDictionaries>
        <foo:SharedResourceDictionary  Source="pack://application:,,,/foo.Client.Common;component/UIStyles/Colours.xaml" />
    

    有了这个,智能感知就可以工作了,即当你输入类似Style="{StaticResource的东西时,你会得到一个有效样式的列表,但是样式名称带有橙色曲线下划线,并且消息“样式'xyz'无法解析”。 (我不确定这是否是 Resharper - 我已经使用了很长时间,我不知道什么是 R#,什么是标准编辑器!)

    就内存而言,当我实现这个时,我注意到内存使用量下降了 1.5%,所以没有什么惊天动地的。现在我想我会坚持我所拥有的,因为对内存的影响并没有我预期的那么糟糕。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多