当列宽缩小时,WPF DataGrid不会收缩

时间:2010-11-15 16:44:13

标签: wpf wpftoolkit wpfdatagrid

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

我想让数据网格用列缩小它的宽度,所以我没有得到右侧的空白区域。我试图调试代码,据我所知,问题出在DataGridCellsPanel中,但我看不到任何地方可以修复宽度测量。

任何帮助都将不胜感激。

3 个答案:

答案 0 :(得分:3)

我有一段时间没遇到这个问题了,我对此感到非常生气,以至于我为它做了一个丑陋的修复。它不漂亮,但它完成了工作。首先,当水平ScrollBar不可见时,这只是一个问题所以我们需要引用它。一旦加载了所有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;
}

答案 1 :(得分: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();
        }
    }

我仍然需要解决两个网格的宽度协调问题,但它看起来适用于一个网格。

答案 2 :(得分:0)

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

所以我修改了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;
            }
        }         }  

我唯一的问题是滚动条始终存在,即使所有列都适合。

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

有什么可以做的,真正摆脱这个空白区域吗?

莱昂