* column width and tab control

Apr 22, 2009 at 5:45 PM
I've been using the DataGrid in several places in my project without any problems. In most of the DataGrids I've used, I set all of the column widths to auto (usually with a finite MinWidth set) except for one that is set to a width of * in order to fill out the space. This has worked fine, up until now. I've noticed that this trick doesn't work when you put a DataGrid in a TabItem that is part of a TabControl and the TabItem isn't visible when you first open the containing window. It seems like it calculates the ActualWidth of the * column to be equal to the total width of the DataGrid without regard for the presence of the other columns.
I confirmed that the TabControl is the problem, because when I rearrange the TabItems so that the one with the DataGrid is the first item, it works fine. Is this a known bug? Is there a workaround?
Apr 22, 2009 at 6:28 PM
Here's a very simple example:

<Window x:Class="DataGridTabTest.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:tools="clr-namespace:Microsoft.Windows.Controls;assembly=WpfToolkit"
        Name="Window"
        Title="Window1" Height="300" Width="300">
    <Grid>
        <TabControl>
            <TabItem Header="Tab1">
                <tools:DataGrid ItemsSource="{Binding ElementName=Window, Path=People}" AutoGenerateColumns="False">
                    <tools:DataGrid.Columns>
                        <tools:DataGridTextColumn Header="First" Width="Auto" MinWidth="80" Binding="{Binding FirstName}"/>
                        <tools:DataGridTextColumn Header="Last" Width="*" Binding="{Binding LastName}"/>
                    </tools:DataGrid.Columns>
                </tools:DataGrid>
            </TabItem>
            <TabItem Header="Tab2">
                <tools:DataGrid ItemsSource="{Binding ElementName=Window, Path=People}" AutoGenerateColumns="False">
                    <tools:DataGrid.Columns>
                        <tools:DataGridTextColumn Header="First" Width="Auto" MinWidth="80" Binding="{Binding FirstName}"/>
                        <tools:DataGridTextColumn Header="Last" Width="*" Binding="{Binding LastName}"/>
                    </tools:DataGrid.Columns>
                </tools:DataGrid>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

Where the People property of the window is a simple List<Person> of a simple Person class with first and last name properties. The first tab displays correctly with the first column taking up at least 80 units and the second column taking up the rest. When you click on Tab2 however, the DataGrid, which was defined identically to the first, has the first column at the same width, but the second column is wider that it should be and horizontal scroll bars appear at the bottom.
Apr 24, 2009 at 3:23 PM
I have a partial workaround. I added a handler for the TabControl.SelectionChanged event and did this:

        private void MyTabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            Dispatcher.BeginInvoke((Action<TabItem>)delegate(TabItem selectedTab)
            {
                if (selectedTab == MyTab)
                {
                    MyColumn.Width = new DataGridLength(1, DataGridLengthUnitType.Star);
                }
            }
            , System.Windows.Threading.DispatcherPriority.ApplicationIdle, MyTabControl.SelectedItem);
        }

Where MyTab is the not initially selected tab and MyColumn is the * column that was getting the wrong width.
This code causes the column width to be reset after the selection has been changed, at which point it can correctly calculate its width. The only problem, other than general hackyness of it, the control will brief flash the incorrectly measured columns before it sets them to the correct values.
Apr 29, 2009 at 2:22 PM
Has anybody else seen this problem? Does anybody else have a better workaround?