我正在使用 wpf 数据网格,并且正在寻找一种方法来在用户调整其中一个时设置所有行的高度。我知道数据网格有一个 RowHeight 属性,可以一次设置所有的行高,但是如何捕捉单个行高的变化让我无法理解
4 回答
没有任何事件可以直接用于此目的。您可以做的是使用在调整行大小和其他内容时触发的另一个事件。我现在正在考虑的事件是 PreviewMouseUp,如果您使用数据网格,当您在任何地方释放鼠标按钮时都会释放它。
您可以做的是,当事件被触发时,您可以检查所有行的行高并找到不同的行,然后用它更新所有行。
我通过反复试验得出了这一点,只要您使用的是 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;
}
})
});
}
@阿兰
你还记得这背后的理由吗?
我可以告诉你:如果你删除两行以取消设置并重置项目源(这确实会减慢整个过程),你调整大小的行将明确设置其高度。
似乎当您调整行的大小时,您会直接更改其高度,这会覆盖您为该行设置的 dataGrid 的 RowHeight 属性的任何值。所以基本上,这就是你能得到的:
dataGrid 的 RowHeight = 20
您将一行的高度(例如第 5 行)更改为 30 => 此行的高度设置为 30,而 dataGrid 的行高度设置为 30。到目前为止一切都很好。
现在,将另一行的高度改回 20(比如第二行)。您将此行的高度设置为 20,将 DataGrid'RowHeight 设置为 20,这会将所有其他行设置为 20,除了保持在 30 的第 5 行。(因为它之前被强制设置为这个值)
清空源并重置它会强制重新加载每一行并考虑 dataGrid 的 RowHeight,从而消除了问题。
据我所知,当您调整行高时不会引发任何事件。
我的第一个建议是设置 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 属性)和用能绑定两个高度属性的魔法来改变它。