【问题标题】:Override resource in XAML覆盖 XAML 中的资源
【发布时间】:2013-03-06 09:42:36
【问题描述】:

我有关注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。但我想覆盖UserControl 中使用的Resource(在我的示例中为ColorKey)。但我得到了例外:

项目已添加。字典中的键:'ColorKey' 正在添加的键:'ColorKey'

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

感谢您的帮助。

【问题讨论】:

    标签: wpf xaml user-controls resources overriding


    【解决方案1】:

    阅读您的帖子并回复第一个答案后,您似乎正在编写一个需要您跟踪多个样式元素的应用程序。保持它们井井有条且易于维护的最佳方法是使用 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 文件夹中。 BrushesAndColors.xaml 在 StylesAndTemplates.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 更简洁、更易于阅读。

    这可能不是“简单的解决方法” - 但随着您的继续,它肯定会让事情变得更容易。如果不止一个人在从事该项目,它也将帮助其他任何人。将所有内容都定义在一个集中区域中,您可以保持样式和颜色的一致,并且没有人必须筛选不同的页面来查找使用的样式,他们只需引用适当的样式即可。

    这也允许您的控件只编写一次,但通过为其提供不同的样式/模板,您可以更改信息的显示方式 - 有助于保持数据和显示信息的分离:)

    希望这会有所帮助,很抱歉这篇文章很长,但这是我能想到的唯一方法来解释我认为您可以如何最好地解决您的问题(并保持解决问题)。

    【讨论】:

      【解决方案2】:

      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>
      

      【讨论】:

      • 谢谢,我知道我可以添加新的依赖属性并以这种方式解决它。但正如我所写,我发布的只是简化的示例。想象一下,不仅有单个画笔作为资源,还有多个控件模板、样式或其他资源。我不想为要“覆盖”的每个资源添加依赖属性。
      猜你喜欢
      • 1970-01-01
      • 2022-01-28
      • 2013-10-07
      • 1970-01-01
      • 2021-05-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多