【问题标题】:WPF DataGrid doesn't shrink when column width shrinks当列宽缩小时,WPF DataGrid 不会缩小
【发布时间】:2011-05-10 08:35:47
【问题描述】:

我在 WPF 中使用 DataGrid,并希望它缩小到仅适合其列的宽度。它很好地用于初始渲染。当我调整列的大小以使其更宽时,网格也会增长。但是,如果我调整列的大小以使其再次变窄,我会在列的右侧得到空白(我可以看到列标题灰色区域超出了列。

我想让数据网格随着列的宽度缩小,这样我就不会得到右边的空白。我已尝试调试代码,据我所知,问题出在 DataGridCellsPanel 中,但我看不到任何修复宽度测量的地方。

任何帮助将不胜感激。

【问题讨论】:

    标签: wpf wpftoolkit wpfdatagrid


    【解决方案1】:

    不久前我遇到过这个问题,我对此感到非常恼火,以至于我做了一个丑陋的修复。它不漂亮,但它完成了工作。首先,这只是水平滚动条不可见时的问题,因此我们需要对它的引用。一旦加载了所有 DataGridColumns(在我的情况下,全部在 Xaml 中,因此 Loaded 事件),则必须运行此代码,并且它不考虑添加/删除 DataGridColumns,但这是一个简单的修复。

    <DataGrid Name="c_dataGrid"
              Loaded="c_dataGrid_Loaded"
              ...>
        <DataGrid.Columns>
            <DataGridTextColumn ..."/>
            <DataGridTextColumn ..."/>
            <!-- ... -->
    

    然后在 Loaded EventHandler 中,我们获取 DataGrid ScrollViewer 并添加一个侦听器,用于监听 DataGrid 中每个 DataGridColumn 的 ActualWidthProperty 的变化。

    private ScrollViewer m_dataGridScrollViewer = null;
    private void c_dataGrid_Loaded(object sender, RoutedEventArgs e)
    {
        m_dataGridScrollViewer = GetVisualChild<ScrollViewer>(c_dataGrid);
        DependencyPropertyDescriptor dependencyPropertyDescriptor =
            DependencyPropertyDescriptor.FromProperty(DataGridColumn.ActualWidthProperty, typeof(DataGridColumn));
        if (dependencyPropertyDescriptor != null)
        {
            foreach (DataGridColumn column in c_dataGrid.Columns)
            {
                dependencyPropertyDescriptor.AddValueChanged(column, DataGridColumn_ActualWidthChanged);
            }
        }
    }
    

    然后我们根据所有 DataGridColumns 的大小计算 DataGrid 的大小,并添加一个常数 8.0(通常是差值)。

    private void DataGridColumn_ActualWidthChanged(object sender, EventArgs e)
    {
        if (m_dataGridScrollViewer != null)
        {
            if (m_dataGridScrollViewer.ComputedHorizontalScrollBarVisibility != Visibility.Visible)
            {
                double dataGridWidth = 8.0;
                foreach (DataGridColumn column in c_dataGrid.Columns)
                {
                    dataGridWidth += column.ActualWidth;
                }
                c_dataGrid.Width = dataGridWidth;
            }
            else
            {
                c_dataGrid.Width = double.NaN;
            }
        }
    }
    

    如果您想出更好的方法,请告诉我:)

    public static T GetVisualChild<T>(object parent) where T : Visual
    {
        DependencyObject dependencyObject = parent as DependencyObject;
        return InternalGetVisualChild<T>(dependencyObject);
    }
    private static T InternalGetVisualChild<T>(DependencyObject parent) where T : Visual
    {
        T child = default(T);
    
        int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
        for (int i = 0; i < numVisuals; i++)
        {
            Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
            child = v as T;
            if (child == null)
            {
                child = GetVisualChild<T>(v);
            }
            if (child != null)
            {
                break;
            }
        }
        return child;
    }
    

    【讨论】:

    • 这是一个不错的解决方案。我稍微调整了一下,让它改为设置 MaxWidth 属性。这解决了网格扩展超出视觉父级约束的问题。为了更好地封装,我也将其转换为行为。
    • 另外,如果没有调用 DataGridColumn_ActualWidthChanged,请确保在获取 DependencyPropertyDescriptor 时使用 Microsoft.Windows.Controls.DataGridColumn 而不是 System.Windows.Controls.DataGridColumn。
    【解决方案2】:

    这是一个很好的解决方案。我稍微调整了一下,让它改为设置 MaxWidth 属性。这解决了网格扩展超出视觉父级约束的问题。为了更好地封装,我也将其转换为行为。

    这就是我最终的结果。

    public class UpdateWidthOnColumnResizedBehavior : Behavior<DataGrid>
    {
            private static readonly DependencyPropertyDescriptor Descriptor;
    
            static UpdateWidthOnColumnResizedBehavior()
            {
                Descriptor = DependencyPropertyDescriptor.FromProperty(DataGridColumn.ActualWidthProperty, typeof(DataGridColumn));
            }
    
            protected override void OnAttached()
            {
                base.OnAttached();
    
                AssociatedObject.Columns.CollectionChanged += OnColumnsCollectionChanged;
    
                foreach (var column in AssociatedObject.Columns)
                {
                    AddListener(column);
                }
            }
    
            void OnColumnsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                switch (e.Action)
                {
                    case NotifyCollectionChangedAction.Add:
                        foreach (var column in e.NewItems.OfType<DataGridColumn>())
                        {
                            AddListener(column);
                        }
                        break;
                    case NotifyCollectionChangedAction.Remove:
                        foreach (var column in e.OldItems.OfType<DataGridColumn>())
                        {
                            RemoveListener(column);
                        }
                        break;
                    case  NotifyCollectionChangedAction.Replace:
                        foreach (var column in e.NewItems.OfType<DataGridColumn>())
                        {
                            AddListener(column);
                        }
                        foreach (var column in e.OldItems.OfType<DataGridColumn>())
                        {
                            RemoveListener(column);
                        }
                        break;
                }
            }
    
            protected override void OnDetaching()
            {
                base.OnDetaching();
    
                foreach (var column in AssociatedObject.Columns)
                {
                    RemoveListener(column);
                }
            }
    
            private void AddListener(DataGridColumn column)
            {
                Descriptor.AddValueChanged(column, ResizeGrid);
            }
    
            private void RemoveListener(DataGridColumn column)
            {
                Descriptor.RemoveValueChanged(column, ResizeGrid);
            }
    
            private void ResizeGrid(object sender, EventArgs e)
            {
                var columnsWidth = AssociatedObject.Columns.Sum(c => c.ActualWidth);
                AssociatedObject.MaxWidth = columnsWidth + 2;
                AssociatedObject.InvalidateMeasure();
            }
        }
    

    关于两个网格的宽度协调,我还有一些事情要解决,但它看起来适用于一个。

    【讨论】:

    • 看起来不错,下次需要的时候试试这个!
    【解决方案3】:

    您的两种方法似乎都存在小问题。当我将最左边的列向右拖动时,整个网格正在调整大小/在内部滚动(不幸的是,我没有足够的声誉来发布图像)。

    所以我修改了 jjrdk ResizeGrid 函数,所以它计算最后一列的宽度并将它一直延伸到左边。网格 Horizo​​ntalAlignment 和 Horizo​​ntalContentAlignment 必须设置为 Horizo​​ntalAlignment.Stretch.

    void ResizeGrid(object sender, EventArgs e) 
        {
             var scroll = ExTreeHelper.FindVisualChild<ScrollViewer>(AssociatedObject);
    
            if (scroll != null && null != AssociatedObject.Columns && AssociatedObject.Columns.Count > 0)
            {
                var lastColumn = AssociatedObject.Columns.Last();
    
                double dataGridWidth = AssociatedObject.Columns.Sum(c => c.ActualWidth) + 2.0;
    
                if (scroll.ComputedHorizontalScrollBarVisibility != Visibility.Visible)
                {
                    RemoveListener(lastColumn);
    
                    AssociatedObject.Columns.Last().Width =
                        AssociatedObject.Columns.Last().Width.DisplayValue + scroll.ViewportWidth - dataGridWidth;
    
                    AssociatedObject.Width = dataGridWidth + scroll.ViewportWidth - dataGridWidth;
    
                    AddListener(lastColumn);
                }
                else
                {
                    AssociatedObject.HorizontalAlignment = HorizontalAlignment.Stretch;
                    AssociatedObject.HorizontalContentAlignment = HorizontalAlignment.Stretch;
    
                    AssociatedObject.Width = double.NaN;
                }
            }         }  
    

    我遇到的唯一问题是滚动条始终存在,即使所有列都已放好。

    还有一个问题,当所有的列向左折叠时,它开始闪烁。

    有什么办法可以真正摆脱这个空白吗?

    里昂

    【讨论】:

      猜你喜欢
      • 2011-11-02
      • 2017-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多