Hierarchical/nested datagrids row details layout problem

Feb 20, 2009 at 7:49 AM
When I nest datagrids so that I add new datagrid to other grids RowDetailsTemplate, I would expect the layout of the outer grid dynamically change when the dimensions of the inner grids change. However, this seems not to be the case in all situations. The outer grid dynamically increases it's size to show it's content, but it won't decrease it's size after content's size decreases.
 
The following animation demonstrates the problem. When the animated rectangles increase in size the height of the outer grid increases respectively, but when the rectangles start to minimize, the outer grid doesn't minimize. Is this a bug or a feature, and how it possibly can be fixed?

<Window x:Class="Test.Window"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Controls="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
    Width="1000"
    Height="600">
    <Window.Resources>
        <XmlDataProvider x:Key="Data" XPath="Data/Colors/Color">
            <x:XData>
                <Data xmlns="">
                    <Colors>
                        <Color Name="Red">
                            <Test />
                        </Color>
                        <Color Name="Green">
                            <Test />
                        </Color>
                        <Color Name="Blue">
                            <Test />
                        </Color>
                        <Color Name="Orange">
                            <Test />
                        </Color>
                    </Colors>
                </Data>
            </x:XData>
        </XmlDataProvider>
    </Window.Resources>
    <Controls:DataGrid AutoGenerateColumns="False"
                       ItemsSource="{Binding Source={StaticResource Data}}"
                       RowDetailsVisibilityMode="Visible"
                       CanUserAddRows="False"
                       CanUserDeleteRows="False"
                       ScrollViewer.CanContentScroll="False">
        <Controls:DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <Controls:DataGrid DockPanel.Dock="Top"
                                   AutoGenerateColumns="False"
                                   ItemsSource="{Binding XPath=Test}"
                                   RowDetailsVisibilityMode="Visible"
                                   CanUserAddRows="False"
                                   CanUserDeleteRows="False">
                    <Controls:DataGrid.RowDetailsTemplate>
                        <DataTemplate>
                            <Rectangle Width="50"
                                       Height="50"
                                       Fill="Red">
                                <Rectangle.Triggers>
                                    <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                                        <EventTrigger.Actions>
                                            <BeginStoryboard>
                                                <Storyboard Storyboard.TargetProperty="Height">
                                                    <DoubleAnimationUsingKeyFrames Duration="0:0:5"
                                                                                   RepeatBehavior="Forever"
                                                                                   AutoReverse="True">
                                                        <LinearDoubleKeyFrame Value="100" />
                                                    </DoubleAnimationUsingKeyFrames>
                                                </Storyboard>
                                            </BeginStoryboard>
                                        </EventTrigger.Actions>
                                    </EventTrigger>
                                </Rectangle.Triggers>
                            </Rectangle>
                        </DataTemplate>
                    </Controls:DataGrid.RowDetailsTemplate>
                </Controls:DataGrid>
            </DataTemplate>
        </Controls:DataGrid.RowDetailsTemplate>
        <Controls:DataGrid.Columns>
            <Controls:DataGridTextColumn Header="Name"
                                         Binding="{Binding XPath=@Name}" />
        </Controls:DataGrid.Columns>
    </Controls:DataGrid>
</Window>
Coordinator
Feb 20, 2009 at 6:30 PM
Hi annyman,

This is actually by design.  The main scenario that this feature was designed for was scrolling when virtualization is turned on, and we decided that cell sizes should be "grow only" by default.  Basically, if you're scrolling through the grid, as cells become unvirtualized, the minimum cell size will grow to fit the largest cell content.  If we then made the cells shrink as smaller content came into view, you'd see the cells oscillating their width, which can be really distracting and create a jumpy UI.  In addition, shrinking the cells back down would require a costly measure and arrange pass, so we did this as a performance enhancement also. 

We've gotten some requests to turn off this behavior, in particular for the scenario when the ItemsSource changes, and this seems like another valid scenario where you may not want the built-in behavior.  We are considering adding some APIs to enable this in V2, and I've added your request to our internal database.  In addition, in V2 we should have better support for displaying hierarchal data in general.

If you'd like to try to enable this yourself, you have a few options.  One hacky you can do is to force the column widths to update whenever is appropriate in for app.  The way to do this is to set the column width to a small absolute value (like 10) and then back to Auto/SizeToHeader/SizeToCells programmatically.  This will trigger a new measure and arrange and auto-size the columns appropriately to whatever is visible.  I’m not sure what the UI will look like while this is happening since I haven’t tried it out, but if the end user can see it and it looks weird, you could do another hacky thing and take a screenshot of the grid before you change the column widths and put it over the actual grid to hide what’s going on in the background. 

 

If you’d prefer to do things the “right” way, then you’ll have to override Measure and find the largest DesiredWidth for all of the visible columns and set the column width to that value.  However, this is more difficult to do and may result in a performance hit. 

Thanks!
Samantha

May 26, 2009 at 8:32 PM

FYI

The associated enumeration is Microsoft.Windows.Controls.DataGridLength;

Tracy