I have a combo box that I'm setting the background color by editing the template. The template is in a resource dictionary file. I have two different build configurations and would like to set the color of the background based on which build it is. My idea is to bind the background in the style to a Tag or something and set the color in the code behind. How is this accomplished? Is there a better way to do this?
MainWindow.xaml
<Grid>
<ComboBox ItemsSource="{Binding ExpenseCategories}" Style="{StaticResource ComboBoxStyleGrayPurple}" Background="{Binding ComboBoxStaticBackground}" SelectedIndex="{Binding SelectedExcatIndex}" Width="150" HorizontalAlignment="Left" />
</Grid>
ResourceDictionary.xaml
These are the relevant lines in the edited template:
<LinearGradientBrush x:Key="ComboBox.Static.Background" EndPoint="0,1" StartPoint="0,0">
<GradientStop Color="#f8f1f9" Offset="0.0"/>
<GradientStop Color="#e4c9e7" Offset="1.0"/>
</LinearGradientBrush>
<ControlTemplate x:Key="ComboBoxTemplate" TargetType="{x:Type ComboBox}">
<Grid x:Name="templateRoot" SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
...
</Grid.ColumnDefinitions>
<Popup
...
</Popup>
<ToggleButton x:Name="toggleButton" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" Style="{StaticResource ComboBoxToggleButton}"/>
<ContentPresenter .../>
</Grid>
<ControlTemplate.Triggers>
...
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border x:Name="templateRoot" Background="{StaticResource ComboBox.Static.Background}" BorderBrush="{StaticResource ComboBox.Static.Border}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="true">
<Border x:Name="splitBorder" BorderBrush="Transparent" BorderThickness="1" HorizontalAlignment="Right" Margin="0" SnapsToDevicePixels="true" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}">
<Path x:Name="arrow" Data="F1 M 0,0 L 2.667,2.66665 L 5.3334,0 L 5.3334,-1.78168 L 2.6667,0.88501 L0,-1.78168 L0,0 Z" Fill="{StaticResource ComboBox.Static.Glyph}" HorizontalAlignment="Center" Margin="0" VerticalAlignment="Center"/>
</Border>
</Border>
<ControlTemplate.Triggers>
...
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
My idea is to modify the line in the ComboBoxToggleButton
-> Border
-> Background
to bind to something in the ComboBox
in MainWndow.xaml
which then is set in the code behind, but I'm not quite sure how to do this.
MainWindowViewModel.cs
void SetValue()
{
#if BUILD2
LinearGradientBrush build2Brush = new LinearGradientBrush(); // set build2 color
#else
LinearGradientBrush build1Brush = new LinearGradientBrush(); // set build1 color
#endif
}
How is this best accomplished?
You must not handle such layout responsibilities in the view model.
Instead, move it to code-behind (or to the view in general).
You should also define the Color
instances and not the Brush
(for convenience when configuring and referencing the brushes in XAML).
The following example creates a code-behind file for the ResourceDictionary
that defines the resources. To accomplish this, we have to extend ResourceDictionary
. Crucial to this is the partial
keyword in the class declaration and the x:Class
attribute on the XAML root element:
MyResources.xaml
namespace Example
{
using System.Windows;
using System.Windows.Media;
public partial class MyResources : ResourceDictionary
{
#if DEBUG
public static Color ConditionalGradientStopColor1 { get; } = (Color)ColorConverter.ConvertFromString("#f8f1f9");
public static Color ConditionalGradientStopColor2 { get; } = (Color)ColorConverter.ConvertFromString("#e4c9e7");
#else
public static Color ConditionalGradientStopColor1 { get; } = Colors.LightBlue;
public static Color ConditionalGradientStopColor2 { get; } = Colors.DarkBlue;
#endif
}
}
MyResources.xaml
<ResourceDictionary x:Class="Example.MyResources"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Example">
<LinearGradientBrush x:Key="ComboBox.Static.Background"
EndPoint="0,1"
StartPoint="0,0">
<GradientStop Color="{x:Static local:MyResources.ConditionalGradientStopColor1}"
Offset="0.0" />
<GradientStop Color="{x:Static local:MyResources.ConditionalGradientStopColor2}"
Offset="1.0" />
</LinearGradientBrush>
<Style x:Key="TextBoxStyle" TargetType="TextBox">
<Setter Property="Background"
Value="{StaticResource ComboBox.Static.Background}" />
</Style>
</ResourceDictionary>
Then use everything as usual:
MainWindow.xaml
<Window>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<TextBox Style={StaticResource TextBoxStyle}" />
</Window>