I try to create a custom ComboBox called MyComboBox
. It has a button for switching between the previous and next items.
I store the Background color of the base in BaseBackground
. This is useful, as I don't want the FrontGlyph
to have the Background
inherited from the templated parent.
This is my WPF code:
<Style x:Key="{x:Type local:MyComboBox}" TargetType="{x:Type local:MyComboBox}">
</Style.Resources>
<Setter Property="Focusable" Value="False" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.CanContentScroll" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyComboBox}">
<Grid Cursor="Hand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <!-- A glyph will come here -->
<ColumnDefinition Width="*" /> <!-- The base combo box can take as much space as it can. -->
</Grid.ColumnDefinitions>
<Path x:Name="FrontGlyph" Grid.Column="0" Data="M 0.0 16.0 L 6.0 0.0 L 6.0 16.0 Z" Fill="{TemplateBinding BaseBackground}" Stretch="Fill" />
<Grid x:Name="BaseComboBox" Grid.Column="1" Background="{TemplateBinding BaseBackground}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" /> <!-- Previous item -->
<ColumnDefinition Width="Auto" /> <!-- Next item -->
<ColumnDefinition Width="*" /> <!-- Content Presenter -->
<ColumnDefinition Width="Auto" /> <!-- Drop down button -->
</Grid.ColumnDefinitions>
<Button x:Name="Prev" Grid.Column="0" Background="{TemplateBinding Background}" Style="{StaticResource MyUIButton}">
<Path VerticalAlignment="Center" Data="M 4.5 0.5 L 0.5 4.5 L 4.5 8.5 Z" Fill="Black" />
</Button>
<Button x:Name="Next" Grid.Column="1" Background="{TemplateBinding Background}" Style="{StaticResource MyUIButton}">
<Path VerticalAlignment="Center" Data="M 0.5 0.5 L 4.5 4.5 L 0.5 8.5 Z" Fill="Black" />
</Button>
<ContentPresenter x:Name="ContentSite" Grid.Column="2" IsHitTestVisible="False" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" VerticalAlignment="Stretch" HorizontalAlignment="Left" />
<ToggleButton x:Name="ToggleButton" Template="{StaticResource ComboBoxToggleButton}" Grid.Column="3" Focusable="false" ClickMode="Press" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Background="{TemplateBinding Background}" />
<Popup x:Name="Popup" Placement="Bottom" IsOpen="{TemplateBinding IsDropDownOpen}" AllowsTransparency="True" Focusable="False" PopupAnimation="Slide">
<Grid x:Name="DropDown" SnapsToDevicePixels="True" MinWidth="{TemplateBinding ActualWidth}" MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border x:Name="DropDownBorder" BorderThickness="1" BorderBrush="{TemplateBinding Background, Converter={StaticResource LightenBrushColor}, ConverterParameter=0.5}" Background="{TemplateBinding Background}" />
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BaseBackground" Value="Goldenrod" /> <!-- This does not work -->
<!--<Setter TargetName="FrontGlyph" Property="Fill" Value="Goldenrod" />
<Setter TargetName="BaseComboBox" Property="Background" Value="{Binding Path=Fill, ElementName=FrontGlyph}" />--> <!-- These 2 lines do work. -->
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And this is the source code of MyComboBox
:
class MyComboBox : ComboBox
{
public static readonly DependencyProperty BaseBackgroundProperty;
public SolidColorBrush BaseBackground { get { return (SolidColorBrush)GetValue(BaseBackgroundProperty); } set { SetValue(BaseBackgroundProperty, value); } }
static MyComboBox()
{
BaseBackgroundProperty = DependencyProperty.Register("BaseBackground", typeof(SolidColorBrush), typeof(MyComboBox), new FrameworkPropertyMetadata(Brushes.Lime, FrameworkPropertyMetadataOptions.AffectsRender, OnBaseBackgroundPropertyChanged));
}
public MyComboBox()
{
DefaultStyleKey = typeof(MyComboBox);
}
private static void OnBaseBackgroundPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
// This is not called when the trigger tries to set BaseBackground when the mouse is over the control
}
}
When I hover the mouse over the control, it should change colors. I should be able to do this via changing the BaseBackground
, since both FrontGlyph
and BaseComboBox
have their background color bound to that. Nevertheless the code compiles but the change does not happen. Not just on the UI, but if I debug the code, I don't see the change in C# either.
If I change the background color of the FrontGlyph
and bind the BaseComboBox.BackgroundColor
to that, it works nicely.
Could someone explain why the changes of my custom property BaseBackground
is not registered? It must not be the standard "Implement the INotifyPropertyChanged
interface." issue, as I use Brush
as my property and Brushes work pretty well everywhere else. :)
My implementation might look silly. Well, I'm kinda new to WPF. Plus I didn't want to burden you with the whole implementation, just tried to replicate the critical parts.
UPDATE
I've found out that in my source code I set BaseBackground = new SolidColorBrush(...)
if some conditions are fulfilled. If I remove this line of code, now the triggers work and BaseBackground gets assigned the Goldenrod color.
But I wonder, why changing a DependencyProperty from C# code prevents it working from XAML markup. Besides, I need both of them to work.
Thank you.