Mister 832
Mister 832

Reputation: 1221

How to get the width of wpf expander togglebutton in codebehind

I want to build a customcontrol where expandable rows are added to grid. In order to match the columns of the expandable row, I added another grid as expander header and content. However, the columns are slightly tilted to the right (see picture). I think it is because of the header size?

How do I access the width of the togglebutton code, so I can change the columndefinitions accordingly?

enter image description here

Thanks!

Upvotes: 1

Views: 895

Answers (1)

plast1k
plast1k

Reputation: 843

There are a few ways to approach this.

One would be trying to find the width of that togglebutton yourself by looking at the control template and compensating - but this is unreliable as the template can change across .NET versions (and operating systems if I recall correctly) and is messy to implement anyway.

The second way is trying to programatically find the width and compensate that way, but that still requires digging into the control template (see issues above)

The third is to let the layout engine figure things out for you. You can do this by sharing the column width on columns 2-4, and setting the width of column 1 to "*". Doing this initially will yield undesired results however, because the Expander Header template has no way to set the HorizontalContentAlignment.

First Try

With a little of the above mentioned risk, you can fix that by digging around in the template via codebehind, as described here But its still not perfect yet.

Closer

Looks like there is a border or margin somewhere. Lets set the BorderThickness of the expander to 0.

Frustrating

UGH! Better - (the whitespace is gone), but there is still a gap between our grid (red with black border) and the green in .NET 4.5. I could not find the source of this gap in a reasonable amount of time, so I just set the Margin of the expander to 0,0,-1,0. This might need to be compensated for inside the expander depending on content, and brings up suppressed memories of CSS hacks (XAML was suppose to be better, wasn't it?)

End Result:

Final

XAML:

<Window x:Class="Sandbox.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="800" SnapsToDevicePixels="True">
<Window.Resources>
    <DataTemplate x:Key="StretchedHeaderTemplate">
        <Border HorizontalAlignment="Stretch" Loaded="Border_Loaded">
            <ContentPresenter Content="{TemplateBinding Content}"/>
        </Border>
    </DataTemplate>
</Window.Resources>
<Grid Grid.IsSharedSizeScope="True" Margin="15">
    <Grid.ColumnDefinitions>
        <ColumnDefinition x:Name="MainLeft"/>
        <ColumnDefinition x:Name="MainRight"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid Grid.Column="0" Background="AliceBlue">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="100" SharedSizeGroup="Col2"/>
            <ColumnDefinition Width="100" SharedSizeGroup="Col3"/>
            <ColumnDefinition Width="100" SharedSizeGroup="Col4"/>
        </Grid.ColumnDefinitions>
        <Border Grid.Column="0" BorderBrush="Black" BorderThickness="1">
            <TextBlock>Col1</TextBlock>
        </Border>
        <Border Grid.Column="1" BorderBrush="Black" BorderThickness="1">
            <TextBlock>Col2</TextBlock>
        </Border>
        <Border Grid.Column="2" BorderBrush="Black" BorderThickness="1">
            <TextBlock>Col3</TextBlock>
        </Border>
        <Border Grid.Column="3" BorderBrush="Black" BorderThickness="1">
            <TextBlock>Col4</TextBlock>
        </Border>
    </Grid>
    <Grid Grid.Column="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <TextBlock Grid.Column="0" HorizontalAlignment="Center">January</TextBlock>
        <TextBlock Grid.Column="1" HorizontalAlignment="Center">February</TextBlock>
        <TextBlock Grid.Column="2" HorizontalAlignment="Center">March</TextBlock>
    </Grid>
    <StackPanel Grid.Column="0" Grid.Row="1">
        <Expander HeaderTemplate="{StaticResource StretchedHeaderTemplate}" Background="LightGreen" BorderThickness="0" Margin="0,0,-1,0">
            <Expander.Header>
                <Grid HorizontalAlignment="Stretch" Background="LightCoral">
                    <Grid Grid.Column="0">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition/>
                            <ColumnDefinition SharedSizeGroup="Col2"/>
                            <ColumnDefinition SharedSizeGroup="Col3"/>
                            <ColumnDefinition SharedSizeGroup="Col4"/>
                        </Grid.ColumnDefinitions>
                        <Border Grid.Column="0" BorderBrush="Black" BorderThickness="1">
                            <TextBlock>Record1</TextBlock>
                        </Border>
                        <Border Grid.Column="1" BorderBrush="Black" BorderThickness="1">
                            <TextBlock>02.05.2016</TextBlock>
                        </Border>
                        <Border Grid.Column="2" BorderBrush="Black" BorderThickness="1">
                            <TextBlock>05.05.2017</TextBlock>
                        </Border>
                        <Border Grid.Column="3" BorderBrush="Black" BorderThickness="1">
                            <TextBlock>340</TextBlock>
                        </Border>
                    </Grid>
                </Grid>
            </Expander.Header>
        </Expander>
    </StackPanel>
</Grid>

Code Behind:

/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Border_Loaded(object sender, RoutedEventArgs e)
    {
        Border root = (Border)sender;
        ContentPresenter presenter = (ContentPresenter)root.TemplatedParent;
        presenter.HorizontalAlignment = HorizontalAlignment.Stretch;
    }
}

Conclusion: This works, but you might want to consider overriding the control template for the Expander if you find any of it too messy.

Upvotes: 3

Related Questions