调整一个行高时如何设置wpf数据网格的所有行高
Posted
技术标签:
【中文标题】调整一个行高时如何设置wpf数据网格的所有行高【英文标题】:how to set all row heights of the wpf datagrid when one row height is adjusted 【发布时间】:2009-08-19 10:41:58 【问题描述】:我正在使用 wpf 数据网格,并且正在寻找一种方法来在用户调整其中一个时设置所有行的高度。我知道数据网格有一个 RowHeight 属性,可以一次设置所有的行高,但是如何捕捉单个行高的变化让我无法理解
【问题讨论】:
【参考方案1】:没有任何事件可以直接用于此目的。您可以做的是使用在调整行大小和其他内容时触发的另一个事件。我现在想到的事件是PreviewMouseUp,当你在数据网格的任何地方释放鼠标按钮时释放。
您可以做的是,当事件被触发时,您可以检查所有行的行高并找到不同的行,然后用它更新所有行。
【讨论】:
【参考方案2】:我通过反复试验得出了这个结论,只要您使用的是 ItemsSource 数据源,它应该可以正常工作。 它应该与虚拟行一起工作,并且只会导致短暂的视觉暂停并切换(这似乎主要归结为列自动生成,因此可以避免)。
随着 hacks 的发展,它具有简单性和使用预计不会改变的机制的优点。
用户触发操作的启发式可能会得到改进,但我还没有失败。
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;
)
);
【讨论】:
这行得通,虽然虚拟化开启时速度很慢。 对不起,当列虚拟化关闭时..,如果我们打开它,我们无法水平滚动,但行确实调整了大小。 是的,我喜欢你只在有人实际调整大小时才为该功能支付大量费用,但代价高昂。您可能可以以某种方式缓存列,删除源并重新创建它而不重新生成列。 我们删除了将 itemsSource 设置为 null 的行,然后再次设置它。如果正在调整行高并且有人双击其中一个单元格并且没有项目源,我们发现这些行可能会给我们带来问题。它还显着加快了速度。你还记得这背后的基本原理吗? @Aran 恐怕我不记得了 :( 教我不要评论奇怪的代码。如果没有它就可以工作,那么它很有可能是可靠的。【参考方案3】:@阿兰
你还记得这背后的基本原理吗?
我可以告诉你:如果你删除两行以取消设置并重置项目源(这确实会减慢整个过程),你调整大小的行将明确设置其高度。
似乎当您调整行的大小时,您直接更改了它的高度,这会覆盖您为该行设置的 dataGrid 的 RowHeight 属性的任何值。所以基本上,这就是你能得到的:
dataGrid 的 RowHeight = 20
您将一行的高度(比如第 5 行)更改为 30 => 此行的高度设置为 30,而 dataGrid 的行高度设置为 30。到目前为止一切都很好。
现在,将另一行的高度改回 20(比如第二行)。您将此行的高度设置为 20,将 DataGrid'RowHeight 设置为 20,这会将所有其他行设置为 20,除了保持在 30 的第 5 行。(因为它之前被强制设置为这个值)
清空源并重置它会强制重新加载每一行并考虑 dataGrid 的 RowHeight,从而消除了问题。
【讨论】:
很有趣,这正是我们的行为,我一直想看看它,但还没有开始,谢谢。【参考方案4】:据我所知,调整行高时不会引发任何事件。
我的第一个建议是设置 RowStyle 以便在 DataGridRow 的高度属性和数据网格的 RowHeight 属性之间创建绑定 (OneWay),但是 如果在调整大小后检查行的高度,它不会改变,ActualHeight 是调整大小时包含行的“实际”高度的属性,并且 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 不起作用,我真的不知道为什么,我可能在这里遗漏了一些明显的东西......)
这确实有效...有点...因为我使用可视化树来获取 DataGridCellsPresenter 我只得到了可见的:P,但这表明它可以通过这种方式完成。
因此,最后,正确的做法是提供 DataGrid 控件模板,它可以与默认模板一样,但 DataGridCellsPresenter 的 Height 属性数据绑定到 DataGrid 的 RowHeight 属性。
我知道这并没有确切说明如何做到这一点,但你只需要学习(我也是:P) 给redefine a control's template;以某种方式获取默认的 DataGrid 模板(或者,如果您已经在使用另一个那么棒的模板,您可能比我更了解它并且已经知道如何做到这一点,以便将 DataGridCellsPresenter Height 属性自动绑定到 RowHeight DataGrid 属性)和用一点魔法来改变它,让两个高度属性都绑定。
【讨论】:
以上是关于调整一个行高时如何设置wpf数据网格的所有行高的主要内容,如果未能解决你的问题,请参考以下文章