【问题标题】:DataGrid column width doesn't auto-updateDataGrid 列宽不会自动更新
【发布时间】:2011-07-29 18:40:13
【问题描述】:
<DataGridTextColumn Binding="{Binding Name}" Width="*"/>
<DataGridTextColumn Binding="{Binding Change}" Width="Auto"/>

Change 的值更新时,其列不会更新以适应新值。所以列太小了,值被剪掉了。
有什么想法吗?

【问题讨论】:

  • 在您在样式中定义之前,该列不会永远扩展。
  • @sajoshi,如何定义?
  • 如果您将宽度更改为除Auto 以外的任何值,问题就会消失,但如果您需要,Scott 在下面的回答是正确的方法!我遍历了所有自动列 dataGrid.Columns.Where(c =&gt; c.Width.IsAuto) 并做了 Scott 所做的事情。

标签: c# .net wpf xaml datagrid


【解决方案1】:

你试过了吗?

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

【讨论】:

  • 对我来说,这会创建不调整宽度的超宽列。
【解决方案2】:

如果需要,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() 或两个在那里的某个地方(在更新和设置回自动之后)

【讨论】:

    【解决方案3】:

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

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

    以下步骤应该会为您执行此操作(我已包含一个示例应用程序进行演示):

    1) 在您的 DataGridTextColumn 绑定(除您的 * 大小列之外的所有列)中设置 NotifyTargetUpdated=True。
    2) 在 DataGrid 上,将处理程序添加到 TargetUpdated 事件。
    3) 在您的 TargetUpdated 事件处理程序中:
    -- a) 将 DataGrid 的 * 大小列的宽度设置为 0。
    -- b) 在 DataGrid 上调用 UpdateLayout() 方法。
    -- c) 将 DataGrid 的 * 大小列的宽度设置回 new 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
        }
    }
    

    【讨论】:

    • 你是个好人,查理布朗。这是关于如何让我的 WPF DataGrid 变得漂亮的最后一个小细节!
    • 我实现了这个,当第一次显示列时它似乎工作。虽然,当我单击数据网格时,它会将列设置为非常小的大小,即使其中的数据更长。
    • 这对我有用,但是如果我有 ScrollViewer.CanContentScroll="True"(又名虚拟化),程序会崩溃并出现异常,指出“在生成内容时无法调用 StartAt”。 STR 是: 1:用很多行填充数据网格 2:选择底部的一行。 3.按住向上箭头键直到触发异常
    • 有没有人觉得微软把 WPF 丢给了我们一半的实现,只有通过像这样的团队努力(感谢 Scott 和其他人)我们才能让它工作?对不起,我只是在发泄:)
    • 我成功使用了dg.Columns[0].Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
    【解决方案4】:

    我的 listview 也有类似的问题,我在 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;
            }
        }
    

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

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

      • 但这不会解决问题,因为计算 ColumnWidth 很复杂,因为它是基于应用的文本样式。
      猜你喜欢
      • 2012-11-17
      • 1970-01-01
      • 1970-01-01
      • 2012-07-14
      • 1970-01-01
      • 1970-01-01
      • 2017-02-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多