Putting an icon at the right end of a WPF expander control

TripleAntigen picture TripleAntigen · Dec 2, 2010 · Viewed 11k times · Source

Hi I am attempting to put a green tick icon at the right end of a WPF Expander control when a checkbox is set. My code currently is:

<Expander x:Name="ImageExpander">
    <Expander.Header>
        <Grid Width="450">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Label Padding="0">My Header Text</Label>
            <Image Grid.Column="1" Margin="0"
                   Source="C:\...\GreenTick.png" Width="18" />
        </Grid>
    </Expander.Header>
</Expander>

I used a grid to put the icon in the top right corner of the expander. This puts the header text in the usual spot next to the twiddle for expanding the expander. It also puts an icon 450 pixels further along near to the right end of the expander.

I was hoping to have it not hard coded so that no matter how wide the expander grows the icon stays in the right corner. Can anybody advise how to do this?

I tried binding the width of the expander.header to the width of the expander with no luck.

Thanks for any advice!

Answer

Kishore Kumar picture Kishore Kumar · Dec 2, 2010

It is because of the Default Template of the Expander (ToggleButton ContentPresenter). This is the modified template and see this is the result you required

<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfApplication19.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Window.Resources>
    <Style x:Key="ExpanderRightHeaderStyle" TargetType="{x:Type ToggleButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border Padding="{TemplateBinding Padding}">
                        <Grid SnapsToDevicePixels="False" Background="Transparent">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="19"/>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
                            <Grid>
                                <Grid.LayoutTransform>
                                    <TransformGroup>
                                        <TransformGroup.Children>
                                            <TransformCollection>
                                                <RotateTransform Angle="-90"/>
                                            </TransformCollection>
                                        </TransformGroup.Children>
                                    </TransformGroup>
                                </Grid.LayoutTransform>
                                <Ellipse x:Name="circle" Stroke="DarkGray" HorizontalAlignment="Center" VerticalAlignment="Center" Width="19" Height="19"/>
                                <Path x:Name="arrow" Stroke="#666" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="false" Data="M 1,1.5 L 4.5,5 L 8,1.5"/>
                            </Grid>
                            <ContentPresenter HorizontalAlignment="Center" Margin="0,4,0,0" VerticalAlignment="Top" SnapsToDevicePixels="True" Grid.Row="1" RecognizesAccessKey="True"/>
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter Property="Data" TargetName="arrow" Value="M 1,4.5  L 4.5,1  L 8,4.5"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                            <Setter Property="Stroke" TargetName="arrow" Value="#222"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="true">
                            <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                            <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                            <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="ExpanderUpHeaderStyle" TargetType="{x:Type ToggleButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border Padding="{TemplateBinding Padding}">
                        <Grid SnapsToDevicePixels="False" Background="Transparent">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="19"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <Grid>
                                <Grid.LayoutTransform>
                                    <TransformGroup>
                                        <TransformGroup.Children>
                                            <TransformCollection>
                                                <RotateTransform Angle="180"/>
                                            </TransformCollection>
                                        </TransformGroup.Children>
                                    </TransformGroup>
                                </Grid.LayoutTransform>
                                <Ellipse x:Name="circle" Stroke="DarkGray" HorizontalAlignment="Center" VerticalAlignment="Center" Width="19" Height="19"/>
                                <Path x:Name="arrow" Stroke="#666" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="false" Data="M 1,1.5 L 4.5,5 L 8,1.5"/>
                            </Grid>
                            <ContentPresenter HorizontalAlignment="Left" Margin="4,0,0,0" VerticalAlignment="Center" SnapsToDevicePixels="True" Grid.Column="1" RecognizesAccessKey="True"/>
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter Property="Data" TargetName="arrow" Value="M 1,4.5  L 4.5,1  L 8,4.5"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                            <Setter Property="Stroke" TargetName="arrow" Value="#222"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="true">
                            <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                            <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                            <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="ExpanderLeftHeaderStyle" TargetType="{x:Type ToggleButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ToggleButton}">
                    <Border Padding="{TemplateBinding Padding}">
                        <Grid SnapsToDevicePixels="False" Background="Transparent">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="19"/>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
                            <Grid>
                                <Grid.LayoutTransform>
                                    <TransformGroup>
                                        <TransformGroup.Children>
                                            <TransformCollection>
                                                <RotateTransform Angle="90"/>
                                            </TransformCollection>
                                        </TransformGroup.Children>
                                    </TransformGroup>
                                </Grid.LayoutTransform>
                                <Ellipse x:Name="circle" Stroke="DarkGray" HorizontalAlignment="Center" VerticalAlignment="Center" Width="19" Height="19"/>
                                <Path x:Name="arrow" Stroke="#666" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="false" Data="M 1,1.5 L 4.5,5 L 8,1.5"/>
                            </Grid>
                            <ContentPresenter HorizontalAlignment="Center" Margin="0,4,0,0" VerticalAlignment="Top" SnapsToDevicePixels="True" Grid.Row="1" RecognizesAccessKey="True"/>
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter Property="Data" TargetName="arrow" Value="M 1,4.5  L 4.5,1  L 8,4.5"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                            <Setter Property="Stroke" TargetName="arrow" Value="#222"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="true">
                            <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                            <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                            <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="ExpanderHeaderFocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Border>
                        <Rectangle Stroke="Black" StrokeDashArray="1 2" StrokeThickness="1" Margin="0" SnapsToDevicePixels="true"/>
                    </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 SnapsToDevicePixels="False" Background="Transparent">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="19"/>
                                <ColumnDefinition Width="*"/>
                            </Grid.ColumnDefinitions>
                            <Ellipse x:Name="circle" Stroke="DarkGray" HorizontalAlignment="Center" VerticalAlignment="Center" Width="19" Height="19"/>
                            <Path x:Name="arrow" Stroke="#666" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" SnapsToDevicePixels="false" Data="M 1,1.5 L 4.5,5 L 8,1.5"/>
                            <ContentPresenter HorizontalAlignment="Stretch" Margin="4,0,0,0" VerticalAlignment="Center" SnapsToDevicePixels="True" Grid.Column="1" RecognizesAccessKey="True"/>
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsChecked" Value="true">
                            <Setter Property="Data" TargetName="arrow" Value="M 1,4.5  L 4.5,1  L 8,4.5"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Stroke" TargetName="circle" Value="#FF3C7FB1"/>
                            <Setter Property="Stroke" TargetName="arrow" Value="#222"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="true">
                            <Setter Property="Stroke" TargetName="circle" Value="#FF526C7B"/>
                            <Setter Property="StrokeThickness" TargetName="circle" Value="1.5"/>
                            <Setter Property="Stroke" TargetName="arrow" Value="#FF003366"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <Style x:Key="ExpanderStyle1" 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}">
                    <Border SnapsToDevicePixels="true" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3">
                        <DockPanel>
                            <ToggleButton x:Name="HeaderSite" FocusVisualStyle="{StaticResource ExpanderHeaderFocusVisual}" Margin="1" MinHeight="0" MinWidth="0" Style="{StaticResource ExpanderDownHeaderStyle}" Content="{TemplateBinding Header}" ContentTemplate="{TemplateBinding HeaderTemplate}" ContentTemplateSelector="{TemplateBinding HeaderTemplateSelector}" FontFamily="{TemplateBinding FontFamily}" FontSize="{TemplateBinding FontSize}" FontStretch="{TemplateBinding FontStretch}" FontStyle="{TemplateBinding FontStyle}" FontWeight="{TemplateBinding FontWeight}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" DockPanel.Dock="Top" IsChecked="{Binding IsExpanded, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"/>
                            <ContentPresenter x:Name="ExpandSite" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Focusable="false" Visibility="Collapsed" DockPanel.Dock="Bottom"/>
                        </DockPanel>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsExpanded" Value="true">
                            <Setter Property="Visibility" TargetName="ExpandSite" Value="Visible"/>
                        </Trigger>
                        <Trigger Property="ExpandDirection" Value="Right">
                            <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Right"/>
                            <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Left"/>
                            <Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderRightHeaderStyle}"/>
                        </Trigger>
                        <Trigger Property="ExpandDirection" Value="Up">
                            <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Top"/>
                            <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Bottom"/>
                            <Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderUpHeaderStyle}"/>
                        </Trigger>
                        <Trigger Property="ExpandDirection" Value="Left">
                            <Setter Property="DockPanel.Dock" TargetName="ExpandSite" Value="Left"/>
                            <Setter Property="DockPanel.Dock" TargetName="HeaderSite" Value="Right"/>
                            <Setter Property="Style" TargetName="HeaderSite" Value="{StaticResource ExpanderLeftHeaderStyle}"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

  <Expander x:Name="ImageExpander" Style="{DynamicResource ExpanderStyle1}">

    <Expander.Header>

        <Grid >
            <Grid.ColumnDefinitions>
                <ColumnDefinition  />
                <ColumnDefinition Width="auto" />
            </Grid.ColumnDefinitions>
            <Label Padding="0" >My Header Text</Label>
            <Image Grid.Column="1" Margin="0" 
               Source="accounting-pic.jpg" Width="18" />
        </Grid>
    </Expander.Header>
</Expander>