DataGrid 列宽不会自动更新

问题描述 投票:0回答:6
<DataGridTextColumn Binding="{Binding Name}" Width="*"/>
<DataGridTextColumn Binding="{Binding Change}" Width="Auto"/>

Change
的值更新时,其列不会更新以适应新值。因此该列太小并且该值被剪裁。
有什么想法吗?

c# .net wpf xaml datagrid
6个回答
72
投票

DataGrid 将增加列大小以适应数据变长的情况,但当数据长度减少时它不会自动减小列大小。在您的示例中,您右对齐“更改”列,并将其余空间用于“名称”列。

现在,当“更改”属性增长到足以增加列的宽度时,“名称”列拒绝缩小以适应,因此您必须自己强制刷新。

以下步骤应该可以为您完成此操作(我已经提供了一个示例应用程序来演示):

1) 在 DataGridTextColumn 绑定中(除 * 大小的列之外的所有绑定)设置 NotifyTargetUpdated=True。
2) 在 DataGrid 上,向 TargetUpdated 事件添加处理程序。
3) 在您的 TargetUpdated 事件处理程序中:
-- a) 将 DataGrid 的 * 大小列的宽度设置为 0。
-- b) 在 DataGrid 上调用 UpdateLayout() 方法。
-- c) 将 DataGrid 的 * 大小列的宽度设置回新的 DataGridLength(1, DataGridLengthUnitType.Star)

XAML 示例:

<Window x:Class="DataGridTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <CollectionViewSource x:Key="MyObjectCollection" />
    </Window.Resources>
    <DockPanel>
        <Button DockPanel.Dock="Bottom" Content="Click to Make Item 1s Text Longer" Click="Button_Click" />
        <Grid>
            <DataGrid x:Name="dg" ItemsSource="{Binding Source={StaticResource MyObjectCollection}}" AutoGenerateColumns="False" TargetUpdated="dg_TargetUpdated">
                <DataGrid.Columns>
                    <DataGridTextColumn Binding="{Binding First}" Width="1*"/>
                    <DataGridTextColumn Binding="{Binding Last, NotifyOnTargetUpdated=True}"  Width="Auto" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>

    </DockPanel>
</Window>

背后的示例代码:

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.ComponentModel;

namespace DataGridTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private ObservableCollection<MyObject> myObjectList = new ObservableCollection<MyObject>();

        public MainWindow()
        {
            InitializeComponent();
            (this.FindResource("MyObjectCollection") as CollectionViewSource).Source = this.myObjectList;
            this.myObjectList.Add(new MyObject() { First = "Bob", Last = "Jones" });
            this.myObjectList.Add(new MyObject() { First = "Jane", Last = "Doe" });
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.myObjectList[0].Last = "BillyOBrian";
        }

        private void dg_TargetUpdated(object sender, DataTransferEventArgs e)
        {
            dg.Columns[0].Width = 0;
            dg.UpdateLayout();
            dg.Columns[0].Width = new DataGridLength(1, DataGridLengthUnitType.Star);
        }
    }

    public class MyObject : INotifyPropertyChanged
    {
        private string firstName;
        public string First
        {
            get { return this.firstName; }
            set
            {
                if (this.firstName != value)
                {
                    this.firstName = value;
                    NotifyPropertyChanged("First");
                }
            }
        }

        private string lastName;
        public string Last
        {
            get { return this.lastName; }
            set
            {
                if (this.lastName != value)
                {
                    this.lastName = value;
                    NotifyPropertyChanged("Last");
                }
            }
        }

        public MyObject() { }

        #region -- INotifyPropertyChanged Contract --

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        #endregion INotifyPropertyChanged Contract
    }
}

2
投票

我的列表视图也有类似的问题,我在 stackoverflow 上的 how-to-autosize-and-right-align-gridviewcolumn-data-in-wpf 上找到了解决方案。

在我的例子中,它将这段代码添加到列表视图绑定到的可观察集合的 CollectionChanged 事件处理程序中:

void listview_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) {
        // this is a listview control
        GridView view = this.View as GridView;
        foreach(GridViewColumn c in view.Columns) {
            if(double.IsNaN(c.Width)) {
                c.Width = c.ActualWidth;
            }
            c.Width = double.NaN;
        }
    }

它对我有用,尽管有时用户会注意到列上“闪烁”。


1
投票

如果需要,WPF 只会调整数据网格的列宽设置为“自动”,即:内容无法完全显示。因此,当内容的宽度缩小时,列的大小不会调整,因为内容仍然可以完全看到。

我能看到强制 wpf 重新计算列宽度的唯一方法是将它们全部强制为 0,然后在后面的代码中返回到 auto,并抛出一两个 updateLayout() ,但这不是很好编程:-/

基本上,在你的代码后面:

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;

并且您可能需要一个或两个

dg.UpdateLayout()
(可能在更新并设置回自动之后)


0
投票
解决此问题的一种方法是在样式设置中定义列的宽度属性,并将该设置绑定到要绑定的对象的属性。

<DataGridTextColumn Binding="{Binding Change}" ElementStyle="{StaticResource ChangeColumnStyle}"/>

在您的资源词典中:

<Style TargetType="{x:Type DataGridTextColumn }" x:Key="ChangeColumnStyle"> <Setter Property="Width" Value="{Binding ColumnWidth}" </Style>

ColumnWidth 应该是对象的属性。现在,如果您从“更改”属性的设置器更新此属性(通过使用一些自定义算法,考虑字体等内容),并调用:

RaisePropertyChanged("ColumnWidth");

它应该更新您的列宽。

public int Change { get { return m_change; } set { if (m_change != value) { m_change = value; ColumnWidth = WidthAlgo(numberOfCharacters); RaisePropertyChanged("Change"); RaisePropertyChanged("ColumnWidth"); } } }
    

0
投票
对于那些遇到这个问题的人,但是对于

ListView

,我能够利用
Scott's优秀的答案来让它工作:

<ListView x:Name="myThing" ItemsSource="{Binding ACollectionOfStuff, NotifyOnTargetUpdated=True}" TargetUpdated="lv_TargetUpdated"> <ListView.View> <GridView> <GridView.Columns> <GridViewColumn Header="MyHeader" Width="Auto"> <GridViewColumn.CellTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding Path=PropertyOnMyClass}" FontSize="14" Margin="2,5,2,0" /> </StackPanel> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> </GridView.Columns> </GridView> </ListView.View> </ListView>
using System.Windows.Controls;
using System.Windows.Data;

namespace MyCompany.App.Views;

public partial class ThingView : UserControl
{
  public ThingView()
  {
    InitializeComponent();
  }

  private void lv_TargetUpdated(object sender, DataTransferEventArgs e)
  {
    var grid = myThing.View as GridView;
    if (grid != null)
    {
      foreach (var column in grid.Columns)
      {
        if (double.IsNaN(column.Width))
        {
          column.Width = column.ActualWidth;
        }
        column.Width = double.NaN;
      }
    }
  }
}
也能够利用这个优秀答案中的信息:

https://stackoverflow.com/a/1007643/4270426


-2
投票
你尝试过这个吗?

<DataGridTextColumn Binding="{Binding Path= Id}" Header="ID" IsReadOnly="True" Width="1*" />
    
© www.soinside.com 2019 - 2024. All rights reserved.