如何在调整一行高度时设置wpf数据网格的所有行高

时间:2009-08-19 10:41:59

标签: wpf datagrid row-height

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

4 个答案:

答案 0 :(得分:3)

没有任何事件可以直接用于此。您可以做的是使用在调整行和其他内容时触发的另一个事件。我现在想到的事件是PreviewMouseUp,当你在datagrid的任何地方释放鼠标按钮时它会被释放。

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

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

答案 2 :(得分:2)

@Aran

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

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

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

dataGrid的RowHeight = 20

您将一行的高度(比如第五行)更改为30 =>此行的高度设置为30,dataGrid的RowHeight设置为30.到目前为止,一切看起来都不错。

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

清空源并重置它会强制重新加载每一行并考虑dataGrid的RowHeight,这样可以解决问题。

答案 3 :(得分:1)

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

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

尝试之后我想:DataGridRow的ActualHeight从哪里获得它的价值?

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

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

显然,DataGrid不公开API以从DataGridRow获取DataGridCellsPresenter(我发现here

所以我的第一种方法是在填充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不起作用,我真的不知道为什么,我可能会遗漏一些明显的东西......)

这确实有效......有点......因为我使用Visual Tree来获取DataGridCellsPresenter我只得到了可见的:P,但这表明它可以这样做。

所以,最后,正确的方法是提供DataGrid控件模板,除了将DataGridCellsPresenter的Height属性数据绑定到DataGrid的RowHeight属性外,它可以作为默认控件模板。

我知道这并不能确切地说明如何去做,但你只需要学习(我也是这样:P) 至redefine a control's template;以某种方式得到默认的DataGrid模板(或者如果你已经使用了另一个很好的模板,你可能比我更了解它并且已经知道如何实现它以便将DataGridCellsPresenter Height属性自动绑定到RowHeight DataGrid属性)和用一点魔法来改变它,它会同时限制两个高度属性。