【问题标题】:how to set all row heights of the wpf datagrid when one row height is adjusted调整一个行高时如何设置wpf数据网格的所有行高
【发布时间】:2009-08-19 10:41:58
【问题描述】:

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

【问题讨论】:

    标签: wpf datagrid row-height


    【解决方案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 属性)和用一点魔法来改变它,让两个高度属性都绑定。

      【讨论】:

        猜你喜欢
        • 2011-03-02
        • 2023-04-04
        • 2011-02-10
        • 1970-01-01
        • 2010-11-17
        • 1970-01-01
        • 1970-01-01
        • 2010-11-28
        • 1970-01-01
        相关资源
        最近更新 更多