没有CTRL或空格的WPF数据网格多重选择

Ara*_*and 8 wpf selection wpftoolkit wpfdatagrid

WPF Datagrid有两种选择模式,Single或Extended.WPF ListView有第三个 - 多个.此模式允许您单击并选择多行而不按住CTRL或Shift.任何人都知道如何为datagrid做这个?

sum*_*mit 14

我正在创建一个具有类似要求的应用程序,适用于触摸屏和桌面.花了一些时间,我想出的解决方案似乎更清洁.在设计器中,我将以下事件设置器添加到datagrid:

<DataGrid.RowStyle>
   <Style TargetType="DataGridRow" >
     <EventSetter Event="MouseEnter" Handler="MouseEnterHandler"></EventSetter>
     <EventSetter Event="PreviewMouseDown" Handler="PreviewMouseDownHandler"></EventSetter>
   </Style>
</DataGrid.RowStyle>
Run Code Online (Sandbox Code Playgroud)

然后在代码隐藏中,我将事件处理为:

private void MouseEnterHandler(object sender, MouseEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed &&
        e.OriginalSource is DataGridRow row)
    {
        row.IsSelected = !row.IsSelected;
        e.Handled = true;
    }
}

private void PreviewMouseDownHandler(object sender, MouseButtonEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed && 
        e.OriginalSource is FrameworkElement element &&
        GetVisualParentOfType<DataGridRow>(element) is DataGridRow row)
    {
        row.IsSelected = !row.IsSelected;
        e.Handled = true;
    }
}

private static DependencyObject GetVisualParentOfType<T>(DependencyObject startObject)
{
    DependencyObject parent = startObject;

    while (IsNotNullAndNotOfType<T>(parent))
    {
        parent = VisualTreeHelper.GetParent(parent);
    }

    return parent is T ? parent : throw new Exception($"Parent of type {typeof(T)} could not be found");
}

private static bool IsNotNullAndNotOfType<T>(DependencyObject obj)
{
    return obj != null && !(obj is T);
}
Run Code Online (Sandbox Code Playgroud)

以下是帮助方法GetVisualParentByType的代码:

<DataGrid.RowStyle>
   <Style TargetType="DataGridRow" >
     <EventSetter Event="MouseEnter" Handler="MouseEnterHandler"></EventSetter>
     <EventSetter Event="PreviewMouseDown" Handler="PreviewMouseDownHandler"></EventSetter>
   </Style>
</DataGrid.RowStyle>
Run Code Online (Sandbox Code Playgroud)

希望它也有助于其他人.


小智 5

您可以尝试通过以下简单方法来解决此问题,而不必DataGrid通过处理预览鼠标按下事件来修改/继承控件:

TheDataGrid.PreviewMouseLeftButtonDown += 
                 new MouseButtonEventHandler(TheDataGrid_PreviewMouseLeftButtonDown);


void TheDataGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    // get the DataGridRow at the clicked point
    var o = TryFindFromPoint<DataGridRow>(TheDataGrid, e.GetPosition(TheDataGrid));
    // only handle this when Ctrl or Shift not pressed 
    ModifierKeys mods = Keyboard.PrimaryDevice.Modifiers;
    if (o != null && ((int)(mods & ModifierKeys.Control) == 0 &&
                                                (int)(mods & ModifierKeys.Shift) == 0))
    {
        o.IsSelected = !o.IsSelected;
        e.Handled = true;
    }
}

public static T TryFindFromPoint<T>(UIElement reference, Point point)
                where T:DependencyObject
{
    DependencyObject element = reference.InputHitTest(point) as DependencyObject;
    if (element == null) 
        return null;
    else if (element is T) 
        return (T)element;
    else return TryFindParent<T>(element);
}
Run Code Online (Sandbox Code Playgroud)

TryFindFromPoint方法来自Philipp Sumi博客文章,用于DataGridRow从单击的位置获取实例。

通过选中ModifierKeys,您仍然可以将Ctrl和Shift保留为默认行为。

这种方法的唯一缺点是您无法单击并拖动以执行其最初选择的范围选择。


Osk*_*kar 4

工具包中的 DataGrid 不支持此功能,而且.NET 4 附带的 DataGrid 似乎也不会支持此功能。该控件尚未准备好用于生产使用的另一个原因。我会选择以下选项之一:

  1. 使用 ListView/GridView 滚动您自己的网格
  2. 修改工具包中DataGrid的源代码(应该不会太难,因为已经支持扩展选择了?)
  3. 寻找任何可用的商业 WPF DataGrid(它们通常会添加大量有用的功能)

我同意 DataGrid 应该支持这一点,并且我认为您无论如何都应该为此提交错误/建议。也许现在将其纳入 .NET 4 还为时不晚..:)