每个用户控件中合并WPF资源字典 - 是个坏主意吗?

8

我将我的应用程序资源存放在一个单独的DLL中,并使用类似于以下内容在App.xaml中引用它们:

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="pack://application:,,,/MyThemesAssembly;component/Themes/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>

当我编辑在主EXE项目中的窗口时,VS2010设计器不会识别其他程序集中的任何资源,因此我看不到任何应用的样式(这并不是一个真正的问题,因为我总是在XAML视图中工作)。然而,Resharper也不认识这些外部资源名称,在我编辑XAML时会出现许多下划线标记。
我发现,可以通过在每个窗口和用户控件中包含上述XAML来修复VS设计器和Resharper,但这会对内存和/或性能产生不良影响吗?每个窗口都会有一个单独的资源副本吗?

好的,IDE和工具中的错误不应该影响您的代码。此外,在每个控件中包含资源字典是一种容易出错的方式(如果您决定重命名字典或添加另一个字典会怎样?)。 - Vlad
我会尝试在设计模式下添加一个解决问题的小技巧。(也许这可以帮助:public class MyUserControlBase : UserControl { public MyUserControlBase() { if (DesignerProperties.GetIsInDesignMode(this)) LoadExternalDictionariesExplicitlyHere(); ...) - Vlad
1
@Vlad 我已经学会了与波浪线共存的方式 - 修复 Resharper 的方法只是一种“美好的事情”。我认为重命名/添加资源不会成为问题。在我的 XAML 示例中,“Generic.xaml”本身只合并了该程序集中的许多其他资源,因此很容易添加新资源。我更关心的是每个窗口都包含 <MergedDictionaries> 是否会影响应用程序(或 VS2010)的内存/性能。 - Andrew Stephens
性能只有在真正影响到你的时候才需要关注,这点值得引用以下关于过早优化的话语。然而,一个简单的解决方法(例如在每个控件的构造函数中使用 Helpers.LoadDictionariesIfInDesignMode(this))似乎比 XAML 中的多行代码更简洁 :) - Vlad
要修复ReSharper,您仍然可以使用App.xaml定义的MergedDictionaries,但是您需要将MyThemesAssembly作为项目引用,而不是二进制引用... - controlflow
1
@ControlFlow,我在其他地方看到过这个提示,但对我没有用。这会影响MyThemesAssembly项目的类型(它是一个类库),或者xaml资源的构建操作(“Page”)吗? - Andrew Stephens
3个回答

3
我们的应用程序在每个用户控件/视图中引用ResourceDictionary时出现了问题。我不建议这样做。通过使用SharedResourceDictionaries,我们成功将应用程序的内存占用减少了300 MB左右。看起来你的ResourceDictionary将为应用程序中的每个单独的UserControl实例化一次。不要为了修复VS设计器而这样做。

2

请尝试使用VS2012。

我有一个测试项目,其中我正在从外部程序集进行资源字典合并,在我的app.xaml中有以下内容:

<Application x:Class="WpfPackDictionaries.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/WPFCommonLibrary;component/Vectors/Vectors.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

我的mainwindow.xaml文件中,使用了路径(path),并引用了可修改的路径样式ModifiablePathStyle:

<Window xmlns:Control="clr-namespace:WPF.Common.Control;assembly=WPFCommonLibrary"  x:Class="WpfPackDictionaries.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">

    <Grid>
        <Path Style="{StaticResource ModifiablePathStyle}" Fill="Red"/>
        <Control:Jabberwocky />
    </Grid>
</Window>

Intellisense/Resharper(V7.1 10/31(早期访问版本))能够识别这种样式,我没有看到任何波浪线:

enter image description here

所以你尝试在VS2012中工作了吗?


我们最终会转移到VS2012,但仍在等待管理层的$$$! - Andrew Stephens
@AndrewStephens 所有最好的工作都是在尊重管理层的情况下完成的。;-) - ΩmegaMan
@AndrewStephens 使用VS2012 Express版进行XAML工作。它仍然可以编译.Net 3.5/4.0项目,而无需更改.prj或.sln项目。 - ΩmegaMan
@OmegaMan 我在使用Resharper 7.1.25.234(官方版本)的VS2012中尝试了完全相同的操作,但是我发现样式名称下面有波浪线。我也希望智能感知功能能够正常工作(这样我就可以开始输入样式名称,然后按Ctrl+Space键来填写剩余部分)。你那边可以正常工作吗? - Christian Myksvoll

2

VS2012能够“看到”资源,因为VS XAML设计器在设计时加载和执行代码,因此VS可以检查运行时可用的资源。ReSharper从不使用设计时代码执行(因为这要求您的代码始终处于可编译状态),因此XAML支持变得更加复杂。

ReSharper 8.0实现了对BAML反编译的支持,并从引用的二进制程序集中提取XAML文件列表并解析XAML资源。


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