Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF DataGrid AutoSize Issue

Tags:

c#

wpf

datagrid

I`ve recently been trying to get text wrapping working within a WPF (C/4.0) DataGrid, and no matter which solution I implement (All use some form of TextBlock inside a template with wrapping) it confuses the auto height of the grid and results in excessive white space (Set to Yellow for visibility sake) at the bottom of the grid.

My Code: (Commented code is alternate solution to text wrapping, but still results in excessive space)

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <DataGrid Grid.Row="0" AutoGenerateColumns="False" ColumnWidth="*" Name="dgFamilyHistories" IsReadOnly="True" 
                          HorizontalScrollBarVisibility="Disabled" 
                      ItemsSource="{Binding Path=Patient.FamilyHistories}" RowDetailsVisibilityMode="Visible"
                      GridLinesVisibility="All">
        <DataGrid.Resources>
            <Style TargetType="{x:Type DataGridRow}">
                <Setter Property="Height" Value="Auto"/>
            </Style>
            <!--<Style TargetType="{x:Type DataGridCell}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type DataGridCell}">
                            <Border Name="border">
                                <ContentControl Content="{TemplateBinding Content}">
                                    <ContentControl.ContentTemplate>
                                        <DataTemplate>
                                            <DockPanel>
                                                <TextBlock TextWrapping="WrapWithOverflow" TextTrimming="CharacterEllipsis"  
                                                         Width="Auto" Height="Auto" Text="{Binding Text}"/>
                                            </DockPanel>
                                        </DataTemplate>
                                    </ContentControl.ContentTemplate>
                                </ContentControl>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>-->
        </DataGrid.Resources>
        <DataGrid.Background>
            <SolidColorBrush Color="Yellow" />
        </DataGrid.Background>
        <DataGrid.Columns>
            <DataGridTextColumn Header="Date" Binding="{Binding DateEntered, StringFormat={}{0:dd/MM/yyyy}}" Width="85"/>
            <!--<DataGridTextColumn Header="Relation" Binding="{Binding Relation}"/>-->
            <DataGridTemplateColumn Header="Relation">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock TextTrimming="CharacterEllipsis" TextWrapping="Wrap" Text="{Binding Path=Relation}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
            <!--<DataGridTextColumn Header="Illness" Binding="{Binding Illness}"/>-->
            <DataGridTemplateColumn Header="Illness">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock TextTrimming="CharacterEllipsis" TextWrapping="Wrap" Text="{Binding Path=Illness}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
            <!--<DataGridTextColumn Header="Health" Binding="{Binding Health}"/>-->
            <DataGridTemplateColumn Header="Health">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock TextTrimming="CharacterEllipsis" TextWrapping="Wrap" Text="{Binding Path=Health}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
            <DataGridTextColumn Header="Birth Date" Binding="{Binding DateOfBirth, StringFormat={}{0:dd/MM/yyyy}}" Width="85"/>
            <DataGridTextColumn Header="Death Date" Binding="{Binding DateOfDeath, StringFormat={}{0:dd/MM/yyyy}}" Width="85"/>
            <!--<DataGridTextColumn Header="Death Cause" Binding="{Binding CauseOfDeath}"/>-->
            <DataGridTemplateColumn Header="Death Cause">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock TextTrimming="CharacterEllipsis" TextWrapping="Wrap" Text="{Binding Path=CauseOfDeath}"/>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
            <DataGridTextColumn Header="Age" Binding="{Binding Age}" Width="50"/>
        </DataGrid.Columns>
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <Label Name="lblDetails" Content="{Binding Path=Comments}" ContentStringFormat="{}Comments: {0}" Margin="15,0,0,0"/>
                <DataTemplate.Triggers>
                    <DataTrigger Binding="{Binding Path=Comments, Converter={Converters:IsNullStringConverter}}" Value="True">
                        <Setter TargetName="lblDetails" Property="Visibility" Value="Collapsed"/>
                    </DataTrigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>
    <DockPanel Grid.Row="1" Background="Blue">

    </DockPanel>
</Grid>
like image 324
FA Servers Avatar asked Nov 02 '10 16:11

FA Servers


2 Answers

Yes, I've encountered that too, must be a bug. The issue is really not the Wrapping itself but rather that as soon a cell gets smaller than it was, then the Height of DataGrid won't update until it's resized for whatever reason (change size of Window or whatever). I don't have a good solution to this problem but here is some sort of workaround.

Update

Optimized version, using DataGridColumn's instead of TextBlocks. Uses an Attached Property WrapColumn (defaults to false) to know the Columns that wrap.

Xaml. Add local:MainWindow.WrapColumn="True" for every wrapping Column.

<DataGridTemplateColumn Header="Health"
                        local:MainWindow.WrapColumn="True">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <TextBlock TextTrimming="CharacterEllipsis"
                       TextWrapping="Wrap"
                       Text="{Binding Path=Health}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Add an Attached Property

public partial class MainWindow : Window
{
    private static readonly DependencyProperty WrapColumnProperty =
          DependencyProperty.RegisterAttached("WrapColumn",
                                              typeof(bool),
                                              typeof(MainWindow));
    public static void SetWrapColumn(DependencyObject element, bool value)
    {
        element.SetValue(WrapColumnProperty, value);
    }
    public static bool GetWrapColumn(DependencyObject element)
    {
        return (bool)element.GetValue(WrapColumnProperty);
    }

Add a listener for ActualWidth changes for every DataGridColumn that has WrapColumn set to true

public MainWindow()
{
    InitializeComponent();

    DependencyPropertyDescriptor dependencyPropertyDescriptor =
        DependencyPropertyDescriptor.FromProperty(DataGridColumn.ActualWidthProperty, typeof(DataGridColumn));

    if (dependencyPropertyDescriptor != null)
    {
        foreach (DataGridColumn column in c_dataGrid.Columns)
        {
            if (GetWrapColumn(column) == true)
            {
                dependencyPropertyDescriptor.AddValueChanged(column, DataGridColumn_ActualWidthChanged);
            }
        }
    }

    void DataGridColumn_ActualWidthChanged(object sender, EventArgs e)
    {
        c_dataGrid.Width = c_dataGrid.ActualWidth - 1;
        EventHandler eventHandler = null;
        eventHandler = new EventHandler(delegate
        {
            c_dataGrid.Width = double.NaN;
            c_dataGrid.LayoutUpdated -= eventHandler;
        });
        c_dataGrid.LayoutUpdated += eventHandler;
    }
    //...
}
like image 151
Fredrik Hedblad Avatar answered Sep 25 '22 08:09

Fredrik Hedblad


Use this way, to expand your datagrid with proper height and width
   <my:DataGridTemplateColumn Header="{DynamicResource name}"  Width="*" 
                                                           CanUserSort="True" SortMemberPath="Name"
                                                           HeaderStyle="{StaticResource StaffDgColoumnHeaderStyle}">
                                <my:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Style="{StaticResource RowTextblockStyle}" >`enter code here`
                                                <Hyperlink>
                                                    <TextBlock Text="{Binding Path=Name}" ToolTip="{Binding Name}"
                                                               TextWrapping="NoWrap" TextTrimming="CharacterEllipsis"/>
                                                </Hyperlink>
                                            </TextBlock>
                                    </DataTemplate>
                                </my:DataGridTemplateColumn.CellTemplate>
                            </my:DataGridTemplateColumn>

                            <my:DataGridTemplateColumn Header="{DynamicResource sft}"  Width="*" 
                                                           CanUserSort="True" SortMemberPath="ShiftName"
                                                           HeaderStyle="{StaticResource StaffDgColoumnHeaderStyle}">
                                <my:DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding ShiftName}" ToolTip="{Binding ShiftName}"
                                                       Style="{StaticResource RowTextblockStyle}"/>
                                    </DataTemplate>
                                </my:DataGridTemplateColumn.CellTemplate>
                            </my:DataGridTemplateColumn>

See Width ="*" Or Use Width ="Auto" or Width = "20*" as per as your requirement.
like image 33
Goldy Sonata Avatar answered Sep 24 '22 08:09

Goldy Sonata