简体   繁体   中英

WPF DataGrid AutoSize Issue

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>
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.

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;
    }
    //...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM