【问题标题】:How should application wide resources be organized?应如何组织应用程序范围的资源?
【发布时间】:2013-03-01 04:21:40
【问题描述】:

这是场景:

我一直在使用 VS 2010 使用 MEF 编写相当大的 WPF 项目。此解决方案中有多个项目,我的所有样式都有一个 ResourceDictionary

AppStyles.xamlResourceDictionary 位于我的启动项目中,它包含了我对该项目的所有样式。在我的App.xaml 中,我有以下内容:

<Application x:Class="Dionysus.Shell.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         DispatcherUnhandledException="UnhandledException" ShutdownMode="OnMainWindowClose">
<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>

            <ResourceDictionary Source="AppStyles.xaml"/>

    </ResourceDictionary>
</Application.Resources>

现在,这一切都在 VS 2010 的设计模式下完美运行,当我调试时,正确的样式被应用于我的所有控件。但是我最近切换到VS 2012,设计器不再工作了!当我调试它时,它工作得很好,但每当我使用我的一种样式时,如下所示:

<Button Name="btnForward" Height="23" Margin="10,0" Style="{StaticResource DionysusButton}" Grid.Row="2" Grid.Column="0"/>

我在 VS 2012 设计器中收到以下错误:

The resource "DionysusButton" could not be resolved.

我不知道为什么会发生这种情况,我已将我的 Style 重命名,甚至 ResourceDictionary 也无济于事。

我应该在 VS 2012 中以不同的方式执行此操作还是 VS 2012 存在问题?

我发现很多帖子说将我的 AppStyles.xaml ResourceDictionaryx:Name 属性更改为 x:Key 将解决此问题,但我不能这样做,因为它不是 @ 的有效选项987654334@.

提前感谢

-- 更新

我正在使用 Marc 的答案,除了默认样式外,一切似乎都进展顺利。我有以下风格:

 <Style TargetType="DataGrid" x:Name="DataGridStyle"/>

这是我的主要ResourceDictionary

<ResourceDictionary x:Name="Main" 
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">


<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="Styles/AppStyling.xaml" />
</ResourceDictionary.MergedDictionaries>

<Style TargetType="DataGrid" BasedOn="{StaticResource DataGridStyle}"/>

当我不在我的主要ResourceDictionary 中添加Style 标记时,它可以正常工作,但该样式显然并未应用于所有项目。当我添加它时,我得到以下异常:

在“System.Windows.Markup.StaticResourceHolder”上提供值引发异常

想法?

【问题讨论】:

  • 你提到了x:Name,但你没有说这在哪里是相关的——你的任何代码中都没有提到它。你也没有说为什么你不能这样做,这可能有用!
  • 对不起!我已经更新了我的问题。
  • 不,想法。据我所知,一切看起来都很好。例外是一无所有。 DataGridStyle 是空的,还是那里有问题?尝试删除主字典的 x:Name。反正你不应该需要它...
  • 好的,我发现了异常,这是由于我的风格使用x:Name proeprty 而不是x:Key。但样式仍未应用于我的所有DataGrid 控件。

标签: wpf visual-studio-2012 styles resourcedictionary


【解决方案1】:

您是否尝试在您的模块中使用位于 app.xaml 中的样式,并使用 PRISM 导出到 shell 中?模块不应该引用您的应用程序/shell 项目(启动项目)?那么他们可能只是不“了解”包含样式的项目?虽然问题是为什么它在 VS2010 中起作用......请让我知道,如果我误解了你的 MEF 场景,那么我会调整我的答案。

Resources and Prism 有点棘手,我喜欢以下方法,我之前已经发布过,但它也可能对您的情况有所帮助。与将资源放在 app.xaml 中相比,它更适合 PRISM 解决方案:

我通常创建一个单独的样式项目,我从我想要样式的项目中引用它。样式项目具有如下固定结构:

对于每个控件,我创建了一个样式ResourceDictionary。例如对于我的按钮:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Style x:Key="PrimaryButtonStyle" TargetType="Button">
    </Style>

    <Style x:Key="ToolbarButton" TargetType="Button">
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="Margin" Value="3"/>
        <Setter Property="Background" Value="Transparent"></Setter>
    </Style>
</ResourceDictionary>

在一个主要的ResourceDictionary 中,我合并了所有其他字典,在本例中是 IncaDesign.xaml 文件,您可以在上图中看到:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:controls="clr-namespace:Commons.Controls;assembly=Commons">

    <ResourceDictionary.MergedDictionaries>

        <ResourceDictionary Source="Converter/Converter.xaml" />
        <ResourceDictionary Source="Styles/Button.xaml" />
        <ResourceDictionary Source="BitmapGraphics/Icons.xaml" />

    </ResourceDictionary.MergedDictionaries>

    <!-- Default Styles -->
    <Style TargetType="Button" BasedOn="{StaticResource PrimaryButtonStyle}"></Style>
</ResourceDictionary>

请注意我是如何定义默认样式的,它们会自动应用,除非您另外指定。在您想要设置样式的每个窗口或控件中,您只需要引用这个ResourceDictionary。注意源的定义,它是对程序集的引用(/Commons.Styling;component...

<UserControl.Resources>        
    <ResourceDictionary>            
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="/Commons.Styling;component/IncaDesign.xaml" />
        </ResourceDictionary.MergedDictionaries>  
        <!-- Here you can added resources which belong to the UserControl only -->
        <!-- For example: -->
        <DataTemplate x:Kex="UcTemplate" /> 
    </ResourceDictionary>        
</UserControl.Resources>

现在将自动设置默认样式,如果您想显式访问资源,可以使用 StaticResource 来执行此操作。

<Viewbox Height="16" Width="16" Margin="0,0,10,0">
    <ContentControl Content="{StaticResource FileIcon32}" />
</Viewbox>

在我看来,这是一个非常好的解决方案,它适用于非常复杂的解决方案,包括模块化解决方案,例如使用 PRISM 构建的解决方案。

【讨论】:

  • 我非常喜欢这个解决方案,因为它将样式与任何特定项目分开,我唯一不太喜欢的是我必须在每个控件中添加UserControl.Resources,因为正如我所提到的这是一个相当大的应用程序!非常感谢
  • 只是一个简单的问题,在我的很多控件上我已经有一个&lt;UserControl.Resources/&gt; 元素,所以当我添加我的ResourceDictionary 到它时,它要求我为其提供一个x:Key ,但是当我做造型时不起作用,在这些情况下我该怎么办?
  • 嗨,很高兴你喜欢这个解决方案。如果您的 UserControls 已经有一个 ResourceDictionary,只需添加添加对 MergedDictionary 的引用的三行。我将编辑答案,注意第三个代码清单中的注释。
  • 我想补充一点,你可能会遇到这个问题。通常它可以正常工作,但是如果您有很多视图,并且引用了这个 one, big 字典,则可能会导致性能问题。你的字典越大,视图的实例化就越慢,因为资源字典会再次为每个视图实例化!我们回到了您的第一个解决方案,即使当时设计时模式已被破坏。
  • 查看this post 以获取更多信息:) 这很重要:每次控件引用 ResourceDictionary XAML 时都会创建它的新实例。因此,如果您有一个包含 30 个控件的自定义控件库,并且每个控件都引用一个通用字典,那么您将创建 30 个相同的资源字典!
猜你喜欢
  • 1970-01-01
  • 2016-10-10
  • 1970-01-01
  • 1970-01-01
  • 2011-02-21
  • 1970-01-01
  • 2023-03-12
  • 2014-02-03
  • 2011-05-19
相关资源
最近更新 更多