【问题标题】:WPF Datagrid -- programmatic selection of row seems to break multi-select (shift-click multiselect, specifically)WPF Datagrid - 行的编程选择似乎打破了多选(特别是shift-click多选)
【发布时间】:2011-11-01 08:52:38
【问题描述】:

我有一个 WPF DataGrid 控件,其 SelectionUnit 为“FullRow”,SelectionMode 为“Extended”,我以编程方式选择其中的一个项目(通常是第一个项目)。选择有效,但由于某种原因,任何形式的程序选择似乎都会破坏 shift-select 多选功能。

如果我单击 DataGrid 中的另一个项目(因此我刚刚单击的项目是唯一选择的项目),则 shift-select 将起作用。如果我以编程方式选择了该项目,它似乎只会中断。此外,在任何一种情况下,control-click 都可以选择多个项目——似乎只有 shift-select 被破坏了。

我尝试了各种形式的以编程方式选择单个项目,从简单到 myGrid.SelectedIndex = 0,到使用 DataGrid 的 ItemContainerGenerator 来获取 DataGridRow 对象的实例并在其上设置 IsSelected = true,但没有有用。

重新迭代 -- 项目的编程选择有效,但它会破坏 shift-click 选择。

以前有人遇到过这种情况吗?我尝试将焦点设置在以编程方式选择的 DataGridRow 实例上,但似乎没有帮助?

【问题讨论】:

  • 对我来说看起来像是控件中的错误。感觉像是与 SelectedItem 与 SelectedItems 有关,但以编程方式设置 SelectedItems 似乎不起作用。 (不小心添加了这个作为答案而不是先评论,不确定我的删除是否有效)

标签: wpf datagrid multi-select


【解决方案1】:

记住焦点和键盘焦点是有区别的。当您在代码中选择项目时,请检查哪些控件具有键盘焦点/常规焦点。我猜数据网格会失去这个焦点,直到你用鼠标点击它,然后它重新获得使用 ctrl 函数所需的焦点。

我在 C++ 应用程序中托管的 WPF 用户控件中遇到了这个问题。

【讨论】:

  • 我也尝试过以编程方式设置键盘焦点,但无济于事。有趣的是,我的场景和你的一样——在 C++ (MFC) 应用程序中托管 WPF 内容。
【解决方案2】:

我成功地使用反射解决了这个问题:

var method = typeof(DataGrid).GetMethod("HandleSelectionForCellInput", BindingFlags.Instance | BindingFlags.NonPublic);
method.Invoke(MyDataGrid, new object[] { cellToSelect, false, false, false });

【讨论】:

    【解决方案3】:

    在@ezolotko 的 sn-p 的帮助下,我刚刚解决了完全相同的问题。 因为网格会动态生成行,所以我需要订阅 ItemContainerGenerator.StatusChanged 事件并找到代表该元素的行中的第一个单元格。

    要找到我使用的单元格 DataGridHelper class 并将其全部包装在附加的行为中:

    using System.Reflection;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using Speedwell.WPF.Helpers;
    
    namespace Speedwell.WPF.Behaviors
    {
        public static class DataGridSingleRowSelected
        {
            public static readonly DependencyProperty IsSelectionFixEnabledProperty = DependencyProperty.RegisterAttached
            (
                "IsSelectionFixEnabled",
                typeof(bool?),
                typeof(DataGridSingleRowSelected),
                new PropertyMetadata(null, IsSelectionFixEnabledChanged)
            );
    
            public static bool GetIsSelectionFixEnabled(DataGrid element)
            {
                return (bool)element.GetValue(IsSelectionFixEnabledProperty);
            }
    
            public static void SetIsSelectionFixEnabled(DataGrid element, bool value)
            {
                element.SetValue(IsSelectionFixEnabledProperty, value);
            }
    
            private static void IsSelectionFixEnabledChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
            {
                var dataGrid = sender as DataGrid;
                if(dataGrid != null)
                {
                    if(args.OldValue == null)
                    {
                        dataGrid.ItemContainerGenerator.StatusChanged += (s, e) => ContainerStatusChanged(dataGrid, ((ItemContainerGenerator)s));
                    }
                }
            }
    
            private static void ContainerStatusChanged(DataGrid dataGrid, ItemContainerGenerator generator)
            {
                if(generator != null && generator.Status == GeneratorStatus.ContainersGenerated && dataGrid.SelectedItems.Count == 1)
                {
                    var row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromItem(dataGrid.SelectedItems[0]);
                    if(row != null)
                    {
                        var cell = dataGrid.GetCell(row, 0);
                        if(cell != null)
                        {
                            SelectCellMethod.Invoke(dataGrid, new object[] { cell, false, false, false });
                        }
                    }
                }
            }
    
            private static readonly MethodInfo SelectCellMethod = typeof(DataGrid).GetMethod("HandleSelectionForCellInput", BindingFlags.Instance | BindingFlags.NonPublic);
        }
    }
    

    如果您可以看到正确的选择,只能在选择单个(1)行时应用,这正是我需要的,似乎它也需要什么@ jordan0day请求。

    【讨论】:

      【解决方案4】:

      我为这个问题苦苦挣扎了好几天,并尝试了很多我在互联网上找到的东西。最后,我通过研究 DataGrid 的源代码找到了适合我的解决方案。 在 DataGrid 中,我注意到一个名为 _selectionAnchor 的成员变量,并猜测这一定是用户在网格中展开选择的起点。我的解决方案是将此成员设置为所选行的第一个单元格。如果在代码中选择了一行,则此修复可确保在展开选择时它从所选行开始。

      请注意,我使用来自this issue 的代码来启用多选。然后,在文件 MainWindow.xaml.cs 中,我添加了以下代码:

      private void ExampleDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
      {
          if (ExampleDataGrid.SelectedItems.Count > 0)
          {
              ExampleDataGrid.ScrollIntoView(ExampleDataGrid.SelectedItems[0]);
      
              // Make sure that when the user starts to make an extended selection, it starts at this one
              foreach (var cellInfo in ExampleDataGrid.SelectedCells)
              {
                  if (cellInfo.Column.DisplayIndex == 0)
                  {
                      var cell = GetDataGridCell(cellInfo);
                      cell?.Focus();
                      var field = typeof(DataGrid).GetField("_selectionAnchor", BindingFlags.NonPublic | BindingFlags.Instance);
                      field?.SetValue(ExampleDataGrid, cellInfo);
                      break;
                  }
              }
          }
      }
      
      public DataGridCell GetDataGridCell(DataGridCellInfo cellInfo)
      {
          var cellContent = cellInfo.Column.GetCellContent(cellInfo.Item);
          if (cellContent != null)
          {
              return (DataGridCell)cellContent.Parent;
          }
      
          return null;
      }
      

      在 xaml 文件中:

      <vm:CustomDataGrid x:Name="ExampleDataGrid" ItemsSource="{Binding ImportItems}"
          SelectedItemsList="{Binding SelectedImportItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
          AutoGenerateColumns="False" SelectionMode="Extended" IsReadOnly="True" CanUserAddRows="False"
          SelectionChanged="ExampleDataGrid_SelectionChanged">
      

      【讨论】:

      • 感谢分享!
      猜你喜欢
      • 2011-01-30
      • 2011-08-12
      • 2011-01-04
      • 2012-10-23
      • 1970-01-01
      • 2012-03-12
      • 1970-01-01
      • 2016-04-25
      • 2012-04-01
      相关资源
      最近更新 更多