Hi,

I am creating a simple Calendar control (such as the Outlook calendar in Month view) where I can place appointments on days.
The control consists of a UserControl called Calendar with a Grid. During run-time, when the control knows which month to show, this Grid is filled with a number of DayControls. Each DayControl is another UserControl with a header (showing the day) and a ListBox (where the appointments should be shown, this is not implemented yet).

At the moment it looks like this:



What I want is pretty simple: when the mouse is over a certain DayControl, I want the header (this is a StackPanel), the ListBox and the Border around them to both get a different appearance (a golden selected appearance).

I am certain I need to use styles and triggers, but I haven't figured it out properly yet after trying for at least 3 hours...


The code for my DayControl UserControl is this:
xml Code:
  1. <UserControl x:Class="CalendarControlLibrary.Controls.DayControl"
  2.              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3.              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4.              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  5.              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:Controls="clr-namespace:CalendarControlLibrary.Controls" mc:Ignorable="d"
  6.              d:DesignHeight="150" d:DesignWidth="150">
  7.  
  8.     <UserControl.Resources>
  9.         <!-- Colors -->
  10.         <Color x:Key="BlueGradientTop">#A5BFE1</Color>
  11.         <Color x:Key="BlueGradientBottom">#E6EDF7</Color>
  12.         <Color x:Key="GoldGradientTop">#FFB86D</Color>
  13.         <Color x:Key="GoldGradientBottom">#FFE876</Color>
  14.         <Color x:Key="LightBlueGradientTop">#FFFFFF</Color>
  15.         <Color x:Key="LightBlueGradientBottom">#AAE6EDF7</Color>
  16.         <Color x:Key="DarkBlueBorder">#8DAED9</Color>
  17.  
  18.         <!-- Brushes -->
  19.         <LinearGradientBrush x:Key="HeaderBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
  20.             <GradientStop Offset="0" Color="{StaticResource BlueGradientTop}" />
  21.             <GradientStop Offset="1" Color="{StaticResource BlueGradientBottom}" />
  22.         </LinearGradientBrush>
  23.         <LinearGradientBrush x:Key="HeaderSelectedBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
  24.             <GradientStop Offset="0" Color="{StaticResource GoldGradientTop}" />
  25.             <GradientStop Offset="1" Color="{StaticResource GoldGradientBottom}" />
  26.         </LinearGradientBrush>
  27.         <LinearGradientBrush x:Key="ContentBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
  28.             <GradientStop Offset="0" Color="{StaticResource LightBlueGradientTop}" />
  29.             <GradientStop Offset="1" Color="{StaticResource LightBlueGradientBottom}" />
  30.         </LinearGradientBrush>
  31.         <LinearGradientBrush x:Key="ContentSelectedBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
  32.             <GradientStop Offset="0" Color="{StaticResource GoldGradientTop}" />
  33.             <GradientStop Offset="1" Color="{StaticResource GoldGradientBottom}" />
  34.         </LinearGradientBrush>
  35.         <SolidColorBrush x:Key="ControlBorderBrush" Color="{StaticResource DarkBlueBorder}" />
  36.         <SolidColorBrush x:Key="ControlSelectedBorderBrush" Color="{StaticResource GoldGradientBottom}" />
  37.     </UserControl.Resources>
  38.  
  39.     <!-- The border around the Header and Listbox -->
  40.     <Border CornerRadius="2" BorderThickness="2">
  41.    
  42.         <!-- The border style -->
  43.         <Border.Style>
  44.             <Style TargetType="Border">
  45.                 <Setter Property="BorderBrush" Value="{DynamicResource ControlBorderBrush}" />
  46.                 <Style.Triggers>
  47.                     <Trigger Property="Controls:DayControl.IsMouseOver" Value="True">
  48.                         <Setter Property="BorderBrush" Value="{DynamicResource ControlSelectedBorderBrush}" />
  49.                     </Trigger>
  50.                 </Style.Triggers>
  51.             </Style>
  52.         </Border.Style>
  53.  
  54.         <!-- The Grid that contains the Header StackPanel and Content ListBox -->
  55.         <Grid>
  56.             <Grid.RowDefinitions>
  57.                 <RowDefinition Height="Auto" />
  58.                 <RowDefinition Height="*" />
  59.             </Grid.RowDefinitions>
  60.  
  61.             <!-- The Header StackPanel -->
  62.             <StackPanel x:Name="headerPanel" Grid.Row="0">
  63.                 <TextBlock x:Name="dayLabel" Text="{Binding Path=DayNumber, UpdateSourceTrigger=PropertyChanged}" FontWeight="Bold"
  64.                            Margin="3, 0, 0, 2"/>
  65.  
  66.                 <StackPanel.Style>
  67.                     <Style TargetType="StackPanel">
  68.                         <Setter Property="Background" Value="{DynamicResource HeaderBackgroundBrush}" />
  69.                         <Style.Triggers>
  70.                             <Trigger Property="Controls:DayControl.IsMouseOver" Value="True">
  71.                                 <Setter Property="Background" Value="{DynamicResource HeaderSelectedBackgroundBrush}" />
  72.                             </Trigger>
  73.                         </Style.Triggers>
  74.                     </Style>
  75.                 </StackPanel.Style>
  76.             </StackPanel>
  77.  
  78.             <!-- The Content ListBox -->
  79.             <ListBox Grid.Row="1" x:Name="contentPanel">
  80.                 <ListBox.Style>
  81.                     <Style TargetType="ListBox">
  82.                         <Setter Property="BorderBrush" Value="Transparent" />
  83.                         <Setter Property="Background" Value="{DynamicResource ContentBackgroundBrush}" />
  84.                         <Style.Triggers>
  85.                             <Trigger Property="Controls:DayControl.IsMouseOver" Value="True">
  86.                                 <Setter Property="Background" Value="{DynamicResource ContentSelectedBackgroundBrush}" />
  87.                             </Trigger>
  88.                         </Style.Triggers>
  89.                     </Style>
  90.                 </ListBox.Style>
  91.             </ListBox>
  92.         </Grid>
  93.     </Border>
  94.  
  95. </UserControl>

There is a couple of brushes and colors in the Resources, and my goal is to simply swap the normal brushes out for the selected ones when the mouse enters the DayControl.

In detail:
  1. The StackPanel (header) should go from HeaderBackgroundBrush to HeaderSelectedBackgroundBrush
  2. The ListBox Background should go from ContentBackgroundBrush to ContentSelectedBackgroundBrush
  3. The BorderBrush of the Border (root control) should go from ControlBorderBrush to ControlSelectedBorderBrush


I am trying to do this using a Style for each of these three controls with a Trigger that should run when the mouse is over the current DayControl, so I am testing for the property ControlsayControl.IsMouseOver. (The "Controls:" part is because it is in the Controls namespace).


It doesn't work completely right. For some reason, the Border seems to swap out fine; when my mouse is anywhere over a certain DayControl, the border turns gold.

The header and ListBox don't work though; they only swap out their backgrounds when the mouse is over THEMSELVES. When the mouse is over the header StackPanel, the header becomes gold, but the ListBox remains the default (right image). In the same way, when the mouse is over the ListBox, the ListBox becomes gold, but the header StackPanel now is the default blue again (left image)...


I don't get it; as far as I can see I am using the exact same method on all three controls, but only the border works correctly.

Is it a flaw in my design (is the IsMouseOver property false when the mouse is over a StackPanel, but not when it is over a Border??? ), a typo somewhere, or something completely different...?

Also, is there no way to put the three setters into a single trigger, so that I don't have to create a style for each control? The trigger is the same for all styles so that sounds more logical, but I couldn't figure it out...

Thanks!