3

我正在使用 wpf 数据网格,并且正在寻找一种方法来在用户调整其中一个时设置所有行的高度。我知道数据网格有一个 RowHeight 属性,可以一次设置所有的行高,但是如何捕捉单个行高的变化让我无法理解

4

4 回答 4

3

没有任何事件可以直接用于此目的。您可以做的是使用在调整行大小和其他内容时触发的另一个事件。我现在正在考虑的事件是 PreviewMouseUp,如果您使用数据网格,当您在任何地方释放鼠标按钮时都会释放它。

您可以做的是,当事件被触发时,您可以检查所有行的行高并找到不同的行,然后用它更新所有行。

于 2009-11-25T21:34:18.257 回答
2

我通过反复试验得出了这一点,只要您使用的是 ItemsSource 数据源,它应该可以正常工作。它应该与虚拟行一起工作,并且只会导致短暂的视觉暂停并切换(这似乎主要归结为列自动生成,因此可以避免)。

随着黑客的发展,它具有简单性和使用预计不会改变的机制的优势。

用户触发操作的启发式可能会得到改进,但我还没有失败。

using Microsoft.Windows.Controls;
using Microsoft.Windows.Controls.Primitives;

public static class DataGridExtensions
{
    public static void LinkRowHeightsToUserChange(this DataGrid dataGrid)
    {
        double? heightToApply = null;
        bool userTriggered = false;

        if (dataGrid.RowHeaderStyle == null)
            dataGrid.RowHeaderStyle = new Style(typeof(DataGridRowHeader));
        if (dataGrid.RowStyle == null)
            dataGrid.RowStyle = new Style(typeof(DataGridRow));

        dataGrid.RowStyle.Setters.Add(new EventSetter()
        {
            Event = DataGridRow.SizeChangedEvent,
            Handler = new SizeChangedEventHandler((r, sizeArgs) =>
            {
                if (userTriggered && sizeArgs.HeightChanged)
                        heightToApply = sizeArgs.NewSize.Height;
            })
        });
        dataGrid.RowHeaderStyle.Setters.Add(new EventSetter()
        {
            Event = DataGridRowHeader.PreviewMouseDownEvent,
            Handler = new MouseButtonEventHandler(
                (rh,e) => userTriggered = true)
        });
        dataGrid.RowHeaderStyle.Setters.Add(new EventSetter()
        {
            Event = DataGridRowHeader.MouseLeaveEvent,
            Handler = new MouseEventHandler((o, mouseArgs) =>
            {
                if (heightToApply.HasValue)
                {
                    userTriggered = false;
                    var itemsSource = dataGrid.ItemsSource;
                    dataGrid.ItemsSource = null;
                    dataGrid.RowHeight = heightToApply.Value;
                    dataGrid.ItemsSource = itemsSource;
                    heightToApply = null;
                }
            })
        });
    }
于 2009-11-29T19:53:10.553 回答
2

@阿兰

你还记得这背后的理由吗?

我可以告诉你:如果你删除两行以取消设置并重置项目源(这确实会减慢整个过程),你调整大小的行将明确设置其高度。

似乎当您调整行的大小时,您会直接更改其高度,这会覆盖您为该行设置的 dataGrid 的 RowHeight 属性的任何值。所以基本上,这就是你能得到的:

dataGrid 的 RowHeight = 20

您将一行的高度(例如第 5 行)更改为 30 => 此行的高度设置为 30,而 dataGrid 的行高度设置为 30。到目前为止一切都很好。

现在,将另一行的高度改回 20(比如第二行)。您将此行的高度设置为 20,将 DataGrid'RowHeight 设置为 20,这会将所有其他行设置为 20,除了保持在 30 的第 5 行。(因为它之前被强制设置为这个值)

清空源并重置它会强制重新加载每一行并考虑 dataGrid 的 RowHeight,从而消除了问题。

于 2010-07-13T06:48:09.317 回答
1

据我所知,当您调整行高时不会引发任何事件。

我的第一个建议是设置 RowStyle 以便在 DataGridRow 的高度属性和数据网格的 RowHeight 属性之间创建绑定(OneWay),但是如果您在调整行的大小后检查行的高度,它是不变的,ActualHeight 是调整大小时包含行的“实际”高度的属性,并且 ActualHeight 无法设置,因为“它没有可访问的设置访问器”。

在尝试了这个之后,我想:DataGridRow 的 ActualHeight 从哪里获得它的价值?

我记得这篇文章解释了如何检测单击了哪个单元格和行,还显示了 DataGrid 的默认模板可视树。

通过反复试验(使用上面链接中的可视树图像),我发现是 DataGridCellPresenter 存储了正在使用的高度(实际上我不是 100% 确定这一点,它是第一个具有高度的类改变了自 DataGridCell 以来的可视化树)。

显然 DataGrid 没有公开 API 以从 DataGridRow 获取 DataGridCellsPresenter (正如我在这里发现的那样)

因此,我的第一种方法是在 DataGrid 中获取所有 DataGridCellPresenter(通过可视化树),然后以编程方式在 DataGridPresenter 的 Height 属性和 DataGrid 的 RowHeight 属性之间创建绑定。

这是执行此操作的代码(我的 DataGrid 的实例名称是 dataGrid1):

获取所有 DataGridCellPresenter:

    void GetAllDataGridCellPresenters(DependencyObject parent, List<DataGridCellsPresenter> presenters) 
    {
        int numberOfChildren = VisualTreeHelper.GetChildrenCount(parent);         
        for (int i = 0; i < numberOfChildren; i++)
        {
            if (VisualTreeHelper.GetChild(parent, i) is DataGridCellsPresenter)
            {
                presenters.Add(VisualTreeHelper.GetChild(parent, i) as DataGridCellsPresenter);
            }
            else if (VisualTreeHelper.GetChild(parent, i) != null)
            {
                GetAllDataGridCellPresenters(VisualTreeHelper.GetChild(parent, i), presenters);
            }
            else
                return;
        }
    }

以编程方式在所有这些上设置绑定(当 DataGrid 引发 Loaded 事件时调用它):

    void SetBindingInDataGridPresenter()
    {
        List<DataGridCellsPresenter> presenters = new List<DataGridCellsPresenter>();
        GetAllDataGridCellPresenters(dataGrid1, presenters);
        foreach (DataGridCellsPresenter presenter in presenters)
        {    
            Binding binding = new Binding("RowHeight");
            binding.Source = dataGrid1;
            binding.Mode = BindingMode.TwoWay;
            presenter.SetBinding(DataGridCellsPresenter.HeightProperty, binding);
        }
    }

(注意:将绑定设置为 OneWayToSource 不起作用,我真的不知道为什么,我可能在这里遗漏了一些明显的东西......)

这确实有效......有点......因为我使用可视化树来获取 DataGridCellsPresenter 我只得到了可见的:P,但这表明它可以通过这种方式完成。

因此,最后,正确的做法是提供 DataGrid 控件模板,它可以与默认模板一样,只是将 DataGridCellsPresenter 的 Height 属性数据绑定到 DataGrid 的 RowHeight 属性。

我知道这并没有确切显示如何做到这一点,但你只需要学习(我也是:P)重新定义控件的模板;以某种方式获取默认的 DataGrid 模板(或者,如果您已经在使用另一个那么棒的模板,您可能比我更了解它并且已经知道如何做到这一点,以便将 DataGridCellsPresenter Height 属性自动绑定到 RowHeight DataGrid 属性)和用能绑定两个高度属性的魔法来改变它。

于 2009-11-29T19:08:47.743 回答