覆盖XAML中的资源

时间:2013-03-06 09:42:36

标签: wpf xaml user-controls resources override

我关注UserControl

<UserControl x:Class="MyControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">

    <UserControl.Resources>
        <SolidColorBrush x:Key="ColorKey" Color="Orange"/>
    </UserControl.Resources>

    <Grid Background="{StaticResource ColorKey}">

    </Grid>
</UserControl>

我这样用它:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:OverrideResource"
    Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <SolidColorBrush x:Key="OtherColorKey" Color="Blue"/>
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <local:MyControl Grid.Row="0">
            <local:MyControl.Resources>
                <SolidColorBrush x:Key="ColorKey" Color="Red"/>
            </local:MyControl.Resources>
        </local:MyControl>

        <Grid Grid.Row="1">
            <Grid.Resources>
                <SolidColorBrush x:Key="OtherColorKey" Color="Green"/>
            </Grid.Resources>
            <Grid Background="{StaticResource OtherColorKey}"/>
        </Grid>
    </Grid>
</Window>

覆盖资源OtherColorKey就像我期望的那样;网格具有绿色Background。但我想覆盖Resource(我的示例中为UserControl)中使用的ColorKey。但我得到例外:

  

项目已添加。键入字典:添加'ColorKey'键:'ColorKey'

这只是一个简化的例子,实际上我需要它来完成更复杂的任务。我知道,对于例如,DevExpress使用类似的机制来自定义它们的控件(但是它们不使用字符串作为键,而是使用从ResourceKey派生的对象)。但我无法找到简单的工作示例来自行实现这样的事情。

感谢您的帮助。

2 个答案:

答案 0 :(得分:4)

阅读完帖子并回复第一个答案后,您似乎正在编写一个应用程序,要求您跟踪几个样式元素。保持组织有序且易于维护的最佳方法是使用ResourceDictionary并引用它。

对我来说,根据他们的定义,我可以轻松地分开我的一个,一个用于画笔和颜色,一个用于ControlTemplates和样式(如果项目非常复杂,那么它取决于其他几个因素 - 这只是一个相对简单的项目。)

一旦定义了这些ResourceDictionary文件,您就可以在App.xaml文件中引用它们,这样它们就可以在整个应用程序中应用,而不必总是在页面的实际XAML中重新定义画笔或模板。

所以,App.xaml的外观示例如下:

<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    x:Class="MyColorBlock.App"
    StartupUri="MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Resources/BrushesAndColors.xaml"/>
                <ResourceDictionary Source="Resources/StylesAndTemplates.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Application.Resources>
</Application>

如上所述,这是一个非常简化的示例,因此源文件位于App.xaml所在的同一项目中 - 只在Resources文件夹中。在StylesAndTemplates.xaml之前引用了BrushesAndColors.xaml,因为定义的样式和模板取决于您定义的颜色。

对于ResourceDictionary BrushesAndColors.xaml:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:OverrideResource">

        <SolidColorBrush x:Key="BlueBrush" Color="Blue"/>
        <SolidColorBrush x:Key="RedBrush" Color="Red"/>
        <SolidColorBrush x:Key="GreenBrush" Color="Green"/>

</ResourceDictionary>

画笔与您定义的相同,但现在它们可以在整个应用程序中被其键引用。

对于StylesAndTemplates.xaml:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:OverrideResource">

    <!-- Adding the MergedDictionaries in this ResourceDictionary allows the control templates and styles to reference the colors and brushes defined in BrushesAndColors.xaml. Note: It is a relative link, both files in this example in the same folder "Resources"  -->
    <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="BrushesAndColors.xaml"/>
    </ResourceDictionary.MergedDictionaries>

    <Style x:key="MyControlStyle" TargetType="{x:Type local:MyControl}">
        <Setter Property="HorizontalAlignment" Value="Stretch"/>
        <Setter Property="VerticalAlignment" Value="Stretch"/>
        <Setter Property="Background" Value="{StaticResource RedBrush}"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:MyControl}">
                <!-- by giving the border background the value of {TemplateBinding Background} it is now set based on what the style's property has been defined as -->
                    <Border Background="{TemplateBinding Background}">
                        <TextBlock Text="Red Block Text"/>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


    <!-- since the style is based on a predefined one it inherits that particular style's definition.
        However, the background color of this stylehas been redefined, and will use that background color
        on any control it is applied to instead-->

    <Style x:Key="MyControlStyleTwo" TargetType="{x:Type local:MyControl}" BasedOn="{StaticResource MyControlStyle}">
        <Setter Property="Background" Value="{StaticResource BlueBrush}"/>
    </Style>


</ResourceDictionary>

出于习惯,我仍然引用ResourceDictionary,这需要确保定义的样式和模板可以在创建时找到我引用的资源。

第二种风格,我基于第一种风格,所以我不必重写整个事物 - 但我可以简单地改变它的背景颜色。所以它看起来像第一个,除了背景颜色不同。

对于主窗口 - 稍有变化:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:OverrideResource"
    Title="MainWindow" Height="350" Width="525">

    <Grid Background="{StaticResource BlueBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

      <local:MyControl Style="{StaticResource MyControlStyle}" Grid.Row="0" />
        <local:MyControl Style="{StaticResource MyControlStyleTwo}" Grid.Row="1"/>

    </Grid>
</Window>

您不再需要重新定义与应用程序UI相关的任何信息,从而使XAML更清晰,更易于阅读。

它可能不是“简单的修复” - 但它会让你的事情变得更容易。如果不止一个人正在从事该项目,它也将帮助其他任何人。在集中区域中定义所有内容后,您可以保持样式和颜色的一致性,并且没有人必须筛选不同的页面以查找使用的样式,它们仅引用适当的样式。

这也允许您的控件只能编写一次,但通过给它不同的样式/模板,您可以更改信息的显示方式 - 帮助保持数据和显示信息分开:)

希望这有帮助,对于长篇文章感到抱歉,但这是我能想到的唯一方法来解释我认为你最能解决问题的方法(并保持解决)。

答案 1 :(得分:0)

正在将OtherColorKey添加到2个不同的词典(窗口和网格)。 ColorKey被添加到同一个字典(MyControl)。

更好的方法是在MyControl中声明一个类型为Brush的DependencyProperty并将其设置为:

   <local:MyControl Grid.Row="0" MyBrush="Red" />

在MyControl中,只需将您想要的任何内容绑定到MyBrush属性。

<UserControl x:Class="MyControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" x:Name=Me>

    <Grid Background="{Binding MyBrush, ElementName=Me}">

    </Grid>
</UserControl>