DataGrid 列宽不会自动更新

发布于 2024-10-30 05:19:19 字数 230 浏览 1 评论 0原文

<DataGridTextColumn Binding="{Binding Name}" Width="*"/>
<DataGridTextColumn Binding="{Binding Change}" Width="Auto"/>

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

<DataGridTextColumn Binding="{Binding Name}" Width="*"/>
<DataGridTextColumn Binding="{Binding Change}" Width="Auto"/>

When the value of Change updates, its column doesn't update to fit the new value. So the column stays too small and the value is clipped.
Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

殊姿 2024-11-06 05:19:19

当数据变长时,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
    }
}

The DataGrid will increase column sizes to fit as the data becomes longer, but it does not automatically decrease column sizes when the length of the data decreases. In your example, you're right aligning the 'Change' column, and using the rest of the space for the 'Name' column.

Now, when a 'Change' property grows large enough that it should increase the column's width, the 'Name' column is refusing to shrink to accommodate, so you have to force a refresh yourself.

The following steps should do this for you (I've included a sample app to demo):

1) In your DataGridTextColumn Bindings (all except your * sized column) set NotifyTargetUpdated=True.
2) On your DataGrid, add a handler to the TargetUpdated event.
3) In your TargetUpdated event handler:
-- a) Set the DataGrid's * sized column's width to 0.
-- b) Call the UpdateLayout() method on the DataGrid.
-- c) Set the DataGrid's * sized column's width back to new DataGridLength(1, DataGridLengthUnitType.Star)

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

Example Code Behind:

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
    }
}
纵情客 2024-11-06 05:19:19

我的列表视图也有类似的问题,我在 how-to-autosize-and-right-align-gridviewcolumn-data-in-wpf 位于 stackoverflow 上。

就我而言,它将这段代码添加到列表视图绑定的可观察集合的 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;
        }
    }

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

i have had similar problem with my listview, the solution i found on how-to-autosize-and-right-align-gridviewcolumn-data-in-wpf here on stackoverflow.

In my case it was adding this piece of code into collectionchanged event handler of the observable collection the list view was bound to:

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

It works for me, although sometimes the user can notice "blink" over the columns.

寂寞美少年 2024-11-06 05:19:19

如果需要,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() 或两个(在更新和设置回自动之后可能)

WPF will just resize a datagrid's column width set to Auto if needed, i.e: the content cannot be displayed entirely. So when the content's width shrinks, the column does not resize as the content can still been seen entirely.

the only way I can see to force wpf to recalculate the columns' widths would be to force them all to 0 and then back to auto in the code behind, with one or two updateLayout() thrown in, but this is not very nice programming :-/

basically, in your code behind:

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 you probably need a dg.UpdateLayout() or two somewhere in there (after the update and the setting back to auto probably)

眼中杀气 2024-11-06 05:19:19

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

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

在您的 ResourceDictionary 中:

<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");
         }
      }
   }

One way you could solve this is by defining the width property of the column in a style setting and binding that setting to a property of the object you are binding to.

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

In your ResourceDictionary:

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

ColumnWidth should be a property of your object. Now if you update this property from the setter of your 'Change' property (by using some self-defined algorithm, taking stuff like font into account), and calling:

RaisePropertyChanged("ColumnWidth");

It should update your column width.

 public int Change
   {
      get { return m_change; }
      set
      {
         if (m_change != value)
         {
            m_change = value;
            ColumnWidth = WidthAlgo(numberOfCharacters);
            RaisePropertyChanged("Change");
            RaisePropertyChanged("ColumnWidth");
         }
      }
   }
醉梦枕江山 2024-11-06 05:19:19

你试过这个吗?

<DataGridTextColumn Binding="{Binding Path= Id}"  Header="ID" IsReadOnly="True" Width="1*" />

Have you tried this?

<DataGridTextColumn Binding="{Binding Path= Id}"  Header="ID" IsReadOnly="True" Width="1*" />
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文