wpfxamldatatemplatetogglebutton

XAML: The initial toggle-state of an expander style groupbox is out of sync


The togglebutton of the expander is out of sync. It is styled in a way, that when closed, the arrow points right and when opened points down. However when starting the app the arrow points right but apparently the togglebutton is already checked because the Uniform Grid is shown. After clicking twice on the togglebutton the togglebutton state and the arrow are synchronised. Could someone show me what i am missing here?

Styles and template

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Style x:Key="ExpanderGroupBoxStyle" TargetType="{x:Type ToggleButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <Grid SnapsToDevicePixels="False" Background="Transparent">
                    <Ellipse x:Name="circle" HorizontalAlignment="Center" VerticalAlignment="Center" Width="15" Height="15" 
                         Fill="{DynamicResource ButtonNormalBackgroundFill}" Stroke="DarkGray"/>
                    <Ellipse x:Name="shadow" HorizontalAlignment="Center" VerticalAlignment="Center" Width="13" Height="13" 
                         Fill="{DynamicResource ExpanderShadowFill}" Visibility="Hidden"/>
                    <Path SnapsToDevicePixels="false" x:Name="arrow" VerticalAlignment="Center" HorizontalAlignment="Center" 
                      Stroke="#000" StrokeThickness="2" Data="M1,1 L4,4 7,1" />
                </Grid>

                <ControlTemplate.Triggers>
                    <Trigger Property="IsChecked" Value="true">
                        <Setter Property="Data" TargetName="arrow" Value="M1,1 L4,4 7,1 "/>
                    </Trigger>
                    <Trigger Property="IsChecked" Value="False">
                        <Setter Property="Data" TargetName="arrow" Value="M 2 7 L 5 4 L 2 1"  />
                    </Trigger>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter Property="Stroke" TargetName="circle" Value="#0046D5"/>
                        <Setter Property="Stroke" TargetName="arrow" Value="#222"/>
                        <Setter Property="Visibility" TargetName="shadow" Value="Visible"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
<DataTemplate x:Key="GroupboxAsExpanderHeader">
    <WrapPanel>
        <ToggleButton
            Style="{StaticResource ExpanderGroupBoxStyle}"
            IsChecked="{Binding Path=IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" >
        </ToggleButton>
        <Label Content="Example" Background="#00000000" Foreground="#000" FontWeight="Bold" />
    </WrapPanel>
</DataTemplate>
<Style x:Key="GroupbBoxAsExpanderStyle" TargetType="GroupBox">
    <Setter Property="HeaderTemplate" Value="{StaticResource GroupboxAsExpanderHeader}"></Setter>
    <Setter Property="BorderBrush" Value="#FF88B1D8"></Setter>
    <Style.Triggers>
        <EventTrigger RoutedEvent="ToggleButton.Unchecked">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation Storyboard.TargetProperty="Height" Duration="0:0:.2" To="32" />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
        <EventTrigger RoutedEvent="ToggleButton.Checked">
            <BeginStoryboard>
                <Storyboard>
                    <DoubleAnimation Storyboard.TargetProperty="Height" Duration="0:0:.2" />
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Style.Triggers>
</Style>

Usage

 <GroupBox Margin="10" Height="150" Style="{StaticResource GroupbBoxAsExpanderStyle}">
   <UniformGrid Columns="2">
       <Label Content="Label 1"></Label>
       <Button Content="Button 1"></Button>
       <Label Content="Label 2" />
       <Button Content="Button 2"></Button>
       <Label Content="Label 3" />
       <Button Content="Button 3"></Button>
   </UniformGrid>

PS: Nevermind about the not bindable Label in the HeaderTemplate. This is the next thing on the list.


Solution

  • I solved it by starting from scratch again and using an expander as a base template. For this template i then copied the styling (mainly the border styles) from a groupbox.

    I removed a lot of - for me - not needed styles , like for example the ExpanderRightHeaderStyle. If you need them you can add the styles from the original template again.

    enter image description here

    enter image description here

    Main Window

    <Window x:Class="Expandable_Groupbox.MainWindow"
            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"
            Title="MainWindow" Height="Auto" Width="800">
        <Window.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="DictionaryExpanderStyle.xaml" />
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </Window.Resources>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <StackPanel Grid.Column="1" Grid.Row="1" Margin="10"> 
                <Expander  Style="{DynamicResource ExpanderGroupBoxStyle}"  Header="More Options">
                    <StackPanel Margin="10,4,0,0">
                        <CheckBox Margin="4" Content="Option 1" />
                        <CheckBox Margin="4" Content="Option 2" />
                        <CheckBox Margin="4" Content="Option 3" />
                        <CheckBox Margin="4" Content="Option 3" />
                        <CheckBox Margin="4" Content="Option 3" />
                    </StackPanel>
                </Expander>         
            </StackPanel>
        </Grid>
    </Window>
    
    

    ResourceDict

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    
        <BorderGapMaskConverter x:Key="BorderGapMaskConverter"/>
        <SolidColorBrush x:Key="Expander.Static.Circle.Stroke" Color="#FF333333"/>
        <SolidColorBrush x:Key="Expander.Static.Circle.Fill" Color="#FFFFFFFF"/>
        <SolidColorBrush x:Key="Expander.Static.Arrow.Stroke" Color="#FF333333"/>
        <SolidColorBrush x:Key="Expander.MouseOver.Circle.Stroke" Color="#FF5593FF"/>
        <SolidColorBrush x:Key="Expander.MouseOver.Circle.Fill" Color="#FFF3F9FF"/>
        <SolidColorBrush x:Key="Expander.MouseOver.Arrow.Stroke" Color="#FF000000"/>
        <SolidColorBrush x:Key="Expander.Pressed.Circle.Stroke" Color="#FF3C77DD"/>
        <SolidColorBrush x:Key="Expander.Pressed.Circle.Fill" Color="#FFD9ECFF"/>
        <SolidColorBrush x:Key="Expander.Pressed.Arrow.Stroke" Color="#FF000000"/>
        <SolidColorBrush x:Key="Expander.Disabled.Circle.Stroke" Color="#FFBCBCBC"/>
        <SolidColorBrush x:Key="Expander.Disabled.Circle.Fill" Color="#FFE6E6E6"/>
        <SolidColorBrush x:Key="Expander.Disabled.Arrow.Stroke" Color="#FF707070"/>
        <Style x:Key="ExpanderHeaderFocusVisual">
            <Setter Property="Control.Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Border>
                            <Rectangle Margin="0" StrokeDashArray="1 2" Stroke="Black" SnapsToDevicePixels="true" StrokeThickness="1"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <Style x:Key="ExpanderDownHeaderStyle" TargetType="{x:Type ToggleButton}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                        <Border Padding="{TemplateBinding Padding}">
                            <Grid Background="Transparent" SnapsToDevicePixels="False">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="19"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <Ellipse x:Name="circle" Fill="{StaticResource Expander.Static.Circle.Fill}" HorizontalAlignment="Center" Height="15" 
                                         Stroke="{StaticResource Expander.Static.Circle.Stroke}" VerticalAlignment="Center" Width="15"/>
                                <Path x:Name="arrow" Data="M 2 7 L 5 4 L 2 1" HorizontalAlignment="Center" Stroke="{StaticResource Expander.Static.Arrow.Stroke}" SnapsToDevicePixels="false" StrokeThickness="2" VerticalAlignment="Center"/>
                                <ContentPresenter Grid.Column="1" HorizontalAlignment="Left" Margin="4,0,0,0" RecognizesAccessKey="True" SnapsToDevicePixels="True" VerticalAlignment="Center" />
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsChecked" Value="true">
                                <Setter Property="Data" TargetName="arrow" Value="M1,1 L4,4 7,1"/>
                            </Trigger>
                            <Trigger Property="IsMouseOver" Value="true">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.MouseOver.Circle.Stroke}"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.MouseOver.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.MouseOver.Arrow.Stroke}"/>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="true">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.Pressed.Circle.Stroke}"/>
                                <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.Pressed.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.Pressed.Arrow.Stroke}"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Stroke" TargetName="circle" Value="{StaticResource Expander.Disabled.Circle.Stroke}"/>
                                <Setter Property="Fill" TargetName="circle" Value="{StaticResource Expander.Disabled.Circle.Fill}"/>
                                <Setter Property="Stroke" TargetName="arrow" Value="{StaticResource Expander.Disabled.Arrow.Stroke}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
       
    
        <Style x:Key="ExpanderGroupBoxStyle" TargetType="{x:Type Expander}">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Stretch"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Expander}">
                        <Grid SnapsToDevicePixels="true">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="6"/>
                                <ColumnDefinition Width="Auto"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="6"/>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="*"/>
                                <RowDefinition Height="6"/>
                            </Grid.RowDefinitions>
                            <Border x:Name="Header" Grid.Column="1" Padding="3,1,3,0" Grid.RowSpan="2" Grid.Row="0" >
                                <ToggleButton x:Name="HeaderSite" ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" 
                                              ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}" DockPanel.Dock="Top" FontStretch="{TemplateBinding FontStretch}" 
                                              Foreground="{TemplateBinding Foreground}" 
                                              FocusVisualStyle="{StaticResource ExpanderHeaderFocusVisual}" 
                                              FontStyle="{TemplateBinding FontStyle}" 
                                              FontFamily="{TemplateBinding FontFamily}" 
                                              FontWeight="{TemplateBinding FontWeight}" 
                                              FontSize="{TemplateBinding FontSize}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                              IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource Mode=TemplatedParent}}" 
                                              Margin="1" MinWidth="0" MinHeight="0" Padding="{TemplateBinding Padding}" 
                                              Style="{StaticResource ExpanderDownHeaderStyle}" 
                                              VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/>
                            </Border>
                            <Border Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="4" Grid.RowSpan="3" 
                                    Background="{TemplateBinding Background}" BorderBrush="Transparent" 
                                    BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="4"  />
                            <Border Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="4" Grid.RowSpan="3" 
                                    BorderBrush="Black" BorderThickness="{TemplateBinding BorderThickness}" 
                                    CornerRadius="4" >
                                <Border.OpacityMask>
                                    <MultiBinding ConverterParameter="7" Converter="{StaticResource BorderGapMaskConverter}">
                                        <Binding ElementName="Header" Path="ActualWidth"/>
                                        <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=Self}"/>
                                        <Binding Path="ActualHeight" RelativeSource="{RelativeSource Mode=Self}"/>
                                    </MultiBinding>
                                </Border.OpacityMask>
                                <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3">
                                    <Border BorderBrush="White" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2"/>
                                </Border>
                            </Border>
                            <ContentPresenter Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" x:Name="ExpandSite" Focusable="false"
                                              HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                              Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Visibility="Collapsed"/>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsExpanded" Value="true">
                                <Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
                            </Trigger>
                            <Trigger Property="IsEnabled" Value="false">
                                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>