Override Resource in XAML

I have the following 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> 

and I use it as follows:

 <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> 

Overriding the OtherColorKey resource works as I expect; the grid has a green Background . But I would like to override the Resource that is used in UserControl ( ColorKey in my example). But I get an exception:

Product has already been added. Key in the dictionary: added key "ColorKey": "ColorKey"

This is just a simplified example, in fact I need it for a more complex task. I know that for an example DevExpress uses a similar mechanism to configure its controls (however, they do not use strings as keys, but objects obtained from ResourceKey ). But I can not find a simple working example to implement such a thing on my own.

Thank you for your help.

+6
source share
2 answers

After reading your message and answering the first answer, it seems that you are writing an application that will require you to track several style elements. The best way to keep them organized and easily maintained is to use a ResourceDictionary and reference it.

For me, I’m much more comfortable when I separate mine, based on what they define, one for brushes and colors and one for controls and styles (if the project is extremely complex, it depends on several other factors - it's just for relatively simple project).

Once these ResourceDictionary files have been defined, you must reference them in the App.xaml file so that they can be applied throughout the application, without having to always override Brush or Template in the actual XAML on the page.

So, an example of how App.xaml might look:

 <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> 

As indicated, this is a very simplified example, so the source files are in the same project as App.xaml - only in the "Resources" folder. BrushesAndColors.xaml is referenced before StylesAndTemplates.xaml because the styles and patterns specified depend on the colors you defined.

For 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> 

The brushes are the same as you defined, but now you can simply refer to your key throughout the application.

For 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 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 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> 

Out of habit, I still refer to the ResourceDictionary that I need to make sure that the styles and patterns can find the resources that I refer to when they are created.

The second style, I based it on the first, so I don’t need to rewrite all this, but I can just change the background color. Thus, it will look like the first, except for a different background color.

In the main window - a little change:

 <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> 

You no longer need to redefine any information related to the user interface of the application, keeping the XAML cleaner and easier to read.

It may not just be an β€œeasy fix”, but it will certainly greatly simplify your work. It will also help someone else if more than one person is working on the project. With everything that is defined in a centralized area, you can maintain consistency in styles and colors, and no one should sift through different pages to find which style has been used, they just link to the appropriate one.

It also allows you to record your control only once, but by providing it with different styles / templates, you can change the way information is displayed - helping to save data and information on the display separately :)

Hope this helps, sorry for the long post, but that was the only way I could think of to explain how I think you could best solve your problem (and save its solution).

+4
source

OtherColorKey is added to 2 different dictionaries (window and grid). ColorKey is added to the same dictionary (MyControl).

The best way to approach this is to declare a Brush type DependencyProperty in MyControl and set it like this:

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

In MyControl, just bind everything you want to this MyBrush property.

 <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> 
0
source

All Articles