WPF Datagrid - 行的编程选择似乎打破了多选(特别是shift-click多选)
Posted
技术标签:
【中文标题】WPF Datagrid - 行的编程选择似乎打破了多选(特别是shift-click多选)【英文标题】:WPF Datagrid -- programmatic selection of row seems to break multi-select (shift-click multiselect, specifically) 【发布时间】: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 似乎不起作用。 (不小心添加了这个作为答案而不是先评论,不确定我的删除是否有效) 【参考方案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">
【讨论】:
感谢分享!以上是关于WPF Datagrid - 行的编程选择似乎打破了多选(特别是shift-click多选)的主要内容,如果未能解决你的问题,请参考以下文章
WPF DataGrid怎么实现多行选中,不能使用CheckBox