Search code examples
c#wpfxamlexpander

WPF: Expander.Header - dock control right


I want the red button in the expander header to be docked right. How can I do this? enter image description here

<StackPanel Orientation="Vertical" x:Name="spTest" Margin="10">
    <Border BorderBrush="Black" BorderThickness="1">
        <Expander Margin="5,0,5,0">
            <Expander.Header>
                <Grid Margin="5,0,0,0" HorizontalAlignment="Stretch">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="40"/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="TEXT1 1231521312"  Grid.Column="0" FontSize="18" Foreground="Black" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
                    <TextBlock Grid.Column="1" FontSize="18" FontStyle="Italic" Margin="10,0,10,0" Foreground="Black" VerticalAlignment="Center" Text="Text2"/>
                    <Button x:Name="btnRemove" Grid.Column="2" Width="40" Height="40" Background="#F8CECC" Content="X" FontWeight="Normal" FontSize="18" BorderBrush="#B95753"/>
                </Grid>
            </Expander.Header>
        </Expander>
    </Border>
</StackPanel>

Thank you!!


Solution

  • The issue comes from ContentPresenter used for header in default template. ContentPresenter has it's HorizontalAlignment set not to the Stretch. To change it you could try to bind HorizontalAlignment of the Grid to the HorizontalAlignment of the ContentPresenter.

    <StackPanel Orientation="Vertical" x:Name="spTest" Margin="10">
        <Border BorderBrush="Black" BorderThickness="1">
            <Expander Margin="5,0,5,0">
                <Expander.Header>
                    <Grid Margin="5,0,0,0" 
    
                        HorizontalAlignment="{Binding HorizontalAlignment, RelativeSource={RelativeSource AncestorType=ContentPresenter}, Mode=OneWayToSource}">
    
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="40"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Text="TEXT1 1231521312"  Grid.Column="0" FontSize="18" Foreground="Black" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
                        <TextBlock Grid.Column="1" FontSize="18" FontStyle="Italic" Margin="10,0,10,0" Foreground="Black" VerticalAlignment="Center" Text="Text2"/>
                        <Button x:Name="btnRemove" Grid.Column="2" Width="40" Height="40" Background="#F8CECC" Content="X" FontWeight="Normal" FontSize="18" BorderBrush="#B95753"/>
                    </Grid>
                </Expander.Header>
            </Expander>
        </Border>
    </StackPanel>
    

    Another way, which would work with nested Expander is to set/bind the Grid.Width.

    <Grid Margin="5,0,0,0" Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType=Expander}, Converter={StaticResource SubtractConverter}, ConverterParameter=5}">
    
    public class SubtractConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return 
                (double)value 
                - 20/*Default template: Grid's column width */ 
                - 4/*Default template: margin of ContentPresenter*/ 
                - 2/*Default template:  2*BorderThikness */ 
                - double.Parse(parameter as string) /*Margin of Grid in Header*/;
        }
    
        public object ConvertBack(object value, Type targetTypes, object parameter, CultureInfo culture)
        {
            return value;
        }
    }
    

    Another way would be override default template for Expander see Expander Styles and Templates.