Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Solving DataGrid inconsistent column width sizing

In our application we use datagrids to layout rows filled with templated content and buttons, however a problem occurs intermittently where some of the columns will size themselves sometimes to the minimum width of the column and sometimes to the column header content width. This seems to be something related to the time at which the itemssource is set and when the loading event occurs but I can't pin it down for sure.

Example of incorrect behaviour broken

Example of correct behaviour enter image description here

The itemssource is bound to an ObservableCollection on the viewmodel which populates async using the async and await keywords and a dataservice.

I have attempted to fix the issue by hiding all columns on initialise and then once the itemssource is set and isloaded has been called setting all the columns back to the initial visibility, this seemed to have some affect but did not fix the problem completely.

The xaml for the column definitions

<Style x:Key="MainDataGridColumnHeader" TargetType="{x:Type DataGridColumnHeader}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
                <TextBlock Text="{TemplateBinding Content}" Foreground="{StaticResource HighlightedTextBrush}"
                           Background="Transparent"
                           FontSize="16" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style x:Key="MainDataGridRow" TargetType="{x:Type DataGridRow}">
    <Setter Property="Background" Value="{StaticResource LightBackgroundBrush}" />
    <Setter Property="BorderBrush" Value="{StaticResource Faded10MidBackgroundBrush}"/>
    <Setter Property="BorderThickness" Value="0,0,0,1" />
    <Setter Property="SnapsToDevicePixels" Value="true" />
    <Setter Property="Padding" Value="5"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridRow}">
                <Border x:Name="DGR_Border"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                        Background="{TemplateBinding Background}"
                        SnapsToDevicePixels="True"
                        CornerRadius="0"
                        Margin="0,5"
                        Width="{Binding ActualWidth, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}">
                    <SelectiveScrollingGrid>
                        <SelectiveScrollingGrid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" />
                            <ColumnDefinition Width="*" />
                        </SelectiveScrollingGrid.ColumnDefinitions>
                        <SelectiveScrollingGrid.RowDefinitions>
                            <RowDefinition Height="*" />
                            <RowDefinition Height="Auto" />
                        </SelectiveScrollingGrid.RowDefinitions>
                        <DataGridCellsPresenter Grid.Column="1"
                                            ItemsPanel="{TemplateBinding ItemsPanel}"
                                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                        <DataGridDetailsPresenter Grid.Column="1"
                                              Grid.Row="1"
                                              SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding AreRowDetailsFrozen, ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical}, Converter={x:Static DataGrid.RowDetailsScrollingConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
                                              Visibility="{TemplateBinding DetailsVisibility}" />
                        <DataGridRowHeader Grid.RowSpan="2"
                                       SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
                                       Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Row}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
                    </SelectiveScrollingGrid>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style x:Key="MainDataGridCell" TargetType="{x:Type DataGridCell}">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Foreground" Value="{StaticResource TextBrush}"/>
    <Setter Property="Focusable" Value="False"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type DataGridCell}">
                <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                    <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="IsEnabled" Value="False">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
        </Trigger>
    </Style.Triggers>
</Style>

The xaml for column header, row and cell styles

<DataGrid.Columns>
            <DataGridTemplateColumn x:Name="dateColumn" Header="Race Time" MinWidth="110" Width="Auto" CellTemplate="{StaticResource RacesRaceTimeTemplate}" />
            <DataGridTemplateColumn x:Name="iconColumn"  Width="62" CellTemplate="{StaticResource RacesRaceIconTemplate}"/>
            <DataGridTemplateColumn x:Name="nameColumn" Width="*" CellTemplate="{StaticResource RacesRaceDescriptionTemplate}"/>
            <DataGridTemplateColumn x:Name="favsColumn" Width="auto" Header="Fav / 2nd Fav" CellTemplate="{StaticResource RacesFavSelectionsTemplate}" />
            <DataGridTemplateColumn x:Name="additionalColumn" Width="78" CellTemplate="{StaticResource RacesAdditionalOptionsTemplate}" />
        </DataGrid.Columns>

For now I can mostly resolve the problem by setting hardcoded widths for the columns, but that is not a reasonable solution going forward as we will have variable width content.

Does anyone have a solution for this problem?

like image 742
ndonohoe Avatar asked Jan 14 '15 11:01

ndonohoe


2 Answers

Did you try setting the min width of all columns, then specify the width based on percentage

<DataGrid.Columns>
        <DataGridTemplateColumn x:Name="dateColumn" MinWidth="110" Width="*" Header="Race Time" CellTemplate="{StaticResource RacesRaceTimeTemplate}" />
        <DataGridTemplateColumn x:Name="iconColumn"  MinWidth="62" Width="2*" CellTemplate="{StaticResource RacesRaceIconTemplate}"/>
        <DataGridTemplateColumn x:Name="nameColumn" MinWidth="500" Width="3*" CellTemplate="{StaticResource RacesRaceDescriptionTemplate}"/>
        <DataGridTemplateColumn x:Name="favsColumn" MinWidth="232" Width="3*" Header="Fav / 2nd Fav" CellTemplate="{StaticResource RacesFavSelectionsTemplate}" />
        <DataGridTemplateColumn x:Name="additionalColumn" MinWidth="78" Width="*" CellTemplate="{StaticResource RacesAdditionalOptionsTemplate}" />
</DataGrid.Columns>
like image 135
Huy Hoang Pham Avatar answered Nov 15 '22 13:11

Huy Hoang Pham


you may see this answer.

try to update your width columns programmatically after setting your ItemsSource

foreach (DataGridColumn c in dg.Columns)
    c.Width = 0;

// Update your DG's source here

foreach (DataGridColumn c in dg.Columns)
    c.Width = DataGridLength.Auto; 

and then UpdateLayout your DataGrid.

like image 41
safi Avatar answered Nov 15 '22 13:11

safi