#1,187 – Using an ItemContainerStyle to Change Items in an ItemsControl

One common use when defining a new ItemContainerStyle for an ItemsControl is to do something special with either the currently selected item or the item that the mouse is currently over.  The default template used as an ItemContainerStyle for a ListBox, for example, changes the background and border for both the selected item and the item that the mouse is currently over.

Below is an example where we change the FontWeight for the currently selected item (to SemiBold) and make the item larger, using a transform.  This method uses a trigger to change several properties.

        <Style x:Key="FocusVisual">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <SolidColorBrush x:Key="Item.MouseOver.Background" Color="#1F26A0DA"/>
        <SolidColorBrush x:Key="Item.MouseOver.Border" Color="#a826A0Da"/>
        <SolidColorBrush x:Key="Item.SelectedInactive.Background" Color="#3DDADADA"/>
        <SolidColorBrush x:Key="Item.SelectedInactive.Border" Color="#FFDADADA"/>
        <SolidColorBrush x:Key="Item.SelectedActive.Background" Color="#3D26A0DA"/>
        <SolidColorBrush x:Key="Item.SelectedActive.Border" Color="#FF26A0DA"/>
        
        <Style x:Key="lbDefaultItemContainerStyle" TargetType="{x:Type ListBoxItem}">
            <Setter Property="SnapsToDevicePixels" Value="True"/>
            <Setter Property="Padding" Value="4,1"/>
            <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
            <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ListBoxItem}">
                        <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                            <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="IsMouseOver" Value="True"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.MouseOver.Background}"/>
                                <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.MouseOver.Border}"/>
                                <Setter Property="LayoutTransform">
                                    <Setter.Value>
                                        <ScaleTransform ScaleX="1.5" ScaleY="1.5"/>
                                    </Setter.Value>
                                </Setter>
                                <Setter Property="FontWeight" Value="SemiBold"/>
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Selector.IsSelectionActive" Value="False"/>
                                    <Condition Property="IsSelected" Value="True"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Background}"/>
                                <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedInactive.Border}"/>
                            </MultiTrigger>
                            <MultiTrigger>
                                <MultiTrigger.Conditions>
                                    <Condition Property="Selector.IsSelectionActive" Value="True"/>
                                    <Condition Property="IsSelected" Value="True"/>
                                </MultiTrigger.Conditions>
                                <Setter Property="Background" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Background}"/>
                                <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource Item.SelectedActive.Border}"/>
                            </MultiTrigger>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="TextElement.Foreground" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

The resulting behavior looks like this:
1187-001

Advertisement

#1,072 – Adding Custom Triggers Related to Keyboard Focus

The default control template for the TextBox control changes the color of the Border around the control when the control gets focus.  It does this by using a trigger hooked to the IsKeyboardFocused property.

You can add your own triggers related to keyboard focus by defining a custom property trigger.  The XAML fragment below defines a new Style element that changes the Background of the control when IsKeyboardFocused is true.

    <Window.Resources>
        <Style x:Key="HoneydewFocus" TargetType="TextBox">
            <Style.Triggers>
                <Trigger Property="IsKeyboardFocused" Value="true">
                    <Setter Property="Background" Value="Honeydew"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

    <StackPanel>
        <TextBox Margin="5" Width="80"
                 Style="{StaticResource HoneydewFocus}"/>

        <TextBox Margin="5" Width="80"
                 Style="{StaticResource HoneydewFocus}"/>

        <Button Content="Click Me" HorizontalAlignment="Center"
                Padding="12,5" Margin="5" />
    </StackPanel>

As we tab between the two TextBox controls, the one with keyboard focus will have a Honeydew-colored background, as well as the default blue border.

1072-001

#917 – Changing Something when an Expander Is Expanded

You can use a trigger to change some property in an Expander whenever the Expander is expanded.  You set the trigger to react to a change in the IsExpanded property.

In the example below, we define a trigger that changes the border color for any expander that is expanded.

    <Window.Resources>
        <Style x:Key="changeColorOnExpanded" TargetType="Expander">
            <Setter Property="BorderBrush" Value="DarkGray"/>
            <Setter Property="Margin" Value="10,5"/>
            <Style.Triggers>
                <Trigger Property="IsExpanded" Value="True">
                    <Setter Property="BorderBrush" Value="Crimson"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

    <StackPanel>
        <Expander Style="{StaticResource changeColorOnExpanded}"
                  Header="Great Novels">
            <ScrollViewer>
                <StackPanel>
                    <TextBlock Text="Ulysses"/>
                    <TextBlock Text="The Great Gatsby"/>
                    <TextBlock Text="A Portrait of the Artist as a Young Man"/>
                    <TextBlock Text="Lolita"/>
                </StackPanel>
            </ScrollViewer>
        </Expander>
        <Expander Style="{StaticResource changeColorOnExpanded}"
                  Header="Funny Guys">
            <ScrollViewer>
                <StackPanel>
                    <TextBlock Text="Bill Murray"/>
                    <TextBlock Text="Eddie Murphy"/>
                    <TextBlock Text="Will Ferrell"/>
                    <TextBlock Text="John Cleese"/>
                </StackPanel>
            </ScrollViewer>
        </Expander>
    </StackPanel>

917-001

#362 – Changing the Text on a ToggleButton When a User Clicks On It

It’s reasonable to want to change the text on a ToggleButton when a user clicks on it, so it shows the current state.  You can do this by using a property trigger, which fires when the IsChecked property of the ToggleButton changes.

    <StackPanel HorizontalAlignment="Center" Margin="15">
        <Label Content="Click to arm the electric fence that surrounds your cube:"/>
        <StackPanel>
            <ToggleButton HorizontalAlignment="Center" Margin="5" Padding="5" Width="80">
                <ToggleButton.Style>
                    <Style TargetType="{x:Type ToggleButton}">
                        <Setter Property="Content" Value="Disarmed"/>
                        <Style.Triggers>
                            <Trigger Property="IsChecked" Value="True">
                                <Setter Property="Content" Value="ARMED"/>
                                <Setter Property="Foreground" Value="Red"/>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </ToggleButton.Style>
            </ToggleButton>
        </StackPanel>
    </StackPanel>