3

I have the following xaml:

<Window x:Class="SharedSizeGroupBug.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>

<StackPanel Grid.IsSharedSizeScope="True">
    <ToggleButton IsChecked="False" Name="TB" Content="Toggle" />

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" SharedSizeGroup="DZG" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <TextBlock Text="A1" Width="100" />
        <TextBlock Text="A2" Grid.Column="1" />
    </Grid>

    <Grid Visibility="{Binding IsChecked, ElementName=TB, Converter={StaticResource BooleanToVisibilityConverter}}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" SharedSizeGroup="DZG" />
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>

        <TextBlock Text="B1" Width="200" />
        <TextBlock Text="B2" Grid.Column="1" />
    </Grid>
</StackPanel>
</Window>

When you try this, the initial state the first column is 100 wide. When the button is pressed and the second grid is made visible, the first column is made 200 wide. However, when you press the button again, the column will still be 200 wide.

Abstractor
  • 216
  • 2
  • 12

2 Answers2

5

I was having the same problem, but with Rows instead of columns. I finally defeated it with a custom ivalue binding converter and basically stripping/restoring the shared sized group based on a bound visibility.

Here's the converter:

class VisibilityToSharedSizeGroupConverter : System.Windows.Data.IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (((System.Windows.Visibility)value) == System.Windows.Visibility.Visible) ? parameter : null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return System.Windows.Data.Binding.DoNothing;
    }
}

Here's a XAML example:

<Window.Resources>
    <local:VisibilityToSharedSizeGroupConverter x:Key="VisToShared" />
</Window.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" 
                       SharedSizeGroup="{Binding Converter={StaticResource ResourceKey=VisToShared}, ConverterParameter='LabelsGroup', ElementName=MyLabel1, Path=Visibility}"/>
        </RowDefinition>
    </Grid.RowDefinitions>
</Grid>
Clonkex
  • 3,373
  • 7
  • 38
  • 55
B.O.B.
  • 704
  • 4
  • 10
  • Thanks a lot for posting the solution. I have the same problem right now. Really hating WPF... – Konrad May 30 '19 at 08:41
  • @Konrad Out of curiosity, what UI frameworks do you like? I'm personally finding WPF to be exceptionally easy to use and very fast to develop with. – Clonkex Dec 02 '21 at 02:54
  • 1
    I used `null` instead of an empty string in the value converter because while it worked with an empty string, it complained that an empty string isn't a valid value. – Clonkex Dec 02 '21 at 04:24
  • @Clonkex I can only share my personal opinion but after working with many desktop (Qt, WPF, Sciter) and web/HTML/js based frameworks (React, Vue, Svelte, Angular). I must say that none of the existing desktop UI frameworks beat the developer experience I had with React and Svelte (Vue is also fine). Nowadays if I wanted to create a desktop app I would probably use MAUI/Blazor or just Electron . If I wanted more security I would go for something Rust/C++ based as .NET is too easy to reverse engineer. – Konrad Dec 02 '21 at 10:02
  • 1
    @Clonkex I haven't tested it with null, but if it works, feel free to edit my answer. – B.O.B. Dec 02 '21 at 21:30
0

As far as I know the Width="Auto" does not necessarily update the width as items change.

I believe that what I have done in the past is to set the width = Double.NaN (or set the width = its own actual width then set it to double.NaN) as per this post.

I believe someone found this code by using reflection on the double click of the column border, so this is infact what microsoft does internally to resize the columns

You can implement something similar to that post with the grids instead of the view. You can also put it straight in the toggle's click event (This is also fine with MVVM because the code creates behaviour purely for the User Interface)

Community
  • 1
  • 1
Jason Ridge
  • 1,868
  • 15
  • 27
  • When content inside the grid resizes and becomes smaller (or is removed), the shared size group is correctly recalculated. I think this comes from an issue that WPF assumes that a collapsed element has no size and does not need to be meaured/arranged. – Abstractor Apr 03 '12 at 06:53
  • Yea I think it's cause the size of the Column isn't actually changing (it's just being hidden), so it doesn't know to resize. Did you give the Double.NaN thing a try? – Jason Ridge Apr 03 '12 at 06:55
  • 2
    The only working solution that I found was to remove the SharedSizeGroup name from the ColumnDefintion when IsVisible is changed to false and resetting it when the grid is again displayed. – Abstractor Apr 13 '12 at 11:04