在鼠标左键上切换多个复选框并在 wpf 中拖动



当用户在鼠标左键按下时拖动它时,我想切换 wpf DataGrid 中所有复选框的检查状态。这意味着当用户按下鼠标左键并拖动到DataGrid上时,属于此拖动区域的所有类型为"DataGridCheckBoxColumn"的单元格都应更改检查状态。

我能够通过获取所选单元格的集合并切换复选框状态来实现这一点,但仅当网格中的行很少且垂直滚动条不存在时,它才能正常工作。当我向网格添加更多行以使网格上存在垂直滚动条时,此技术不起作用。它将拖动区域中的复选框和许多其他复选框向下切换网格的视图区域(这是一种分页区域,就好像 DataGrid 将窗口划分为多个页面并将这些复选框选中到每个页面中(。

我试过什么

  1. 通过获取"选定单元格"集合来切换复选框
  2. 通过从可视化树助手中获取蓝色选择框下的复选框进行切换
  3. 通过获取行索引和列
  4. 索引来循环拖动区域下的行和列进行切换

所有方法都会导致相同的行为。 我想了解这种方法的错误在哪里。我用于第一种方法的 xaml 和代码背后的代码是

.xaml

<Window x:Class="MultipleCheckboxSelection.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MultipleCheckboxSelection"
mc:Ignorable="d"
Title="MainWindow" Height="500" Width="800">
<Grid>
<DataGrid AutoGenerateColumns="False" Margin="0,0,0,29" Name="userGrid" SelectionUnit="Cell" 
PreviewMouseLeftButtonUp="userGrid_PreviewMouseLeftButtonUp" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"></DataGridTextColumn>
<DataGridTextColumn Header="Last Name" Binding="{Binding LastName}"></DataGridTextColumn>
<DataGridTextColumn Header="Age" Binding="{Binding Age}" Width="100"/>
<DataGridCheckBoxColumn Header="Column-1"></DataGridCheckBoxColumn>
<DataGridCheckBoxColumn Header="Column-2"></DataGridCheckBoxColumn>
<DataGridCheckBoxColumn Header="Column-3"></DataGridCheckBoxColumn>
<DataGridCheckBoxColumn Header="Column-4"></DataGridCheckBoxColumn>
<DataGridCheckBoxColumn Header="Column-5"></DataGridCheckBoxColumn>
<DataGridCheckBoxColumn Header="Column-6"></DataGridCheckBoxColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>

C#

public partial class MainWindow : Window
{
readonly ObservableCollection<Person> People = new ObservableCollection<Person>();
public MainWindow()
{
InitializeComponent();
for (int i = 0; i < 2000; i++)
{
People.Add(new Person() { FirstName = "First", LastName = "Last", Age = 20 });
}
userGrid.ItemsSource = People;
}
private void userGrid_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
IList<DataGridCellInfo> selectedCells = userGrid.SelectedCells;
foreach (var dataGridCell in selectedCells)
{
if (dataGridCell.Column is DataGridCheckBoxColumn)
{
var checkBox = dataGridCell.Column.GetCellContent(dataGridCell.Item) as CheckBox;
if (null != checkBox)
{
checkBox.IsChecked = !checkBox.IsChecked;
}
}
}
userGrid.UnselectAllCells();
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}

结果图像,以便更好地理解

我正在使用.net 4.6.1。一点帮助将不胜感激。

编辑:

我的应用程序具有不同类型的复选框列。每种类型可以有 0 个或多个始终放在一起的复选框列。这些列由用户在运行时添加,也可以在运行时删除。假设我有 3 种类型的复选框列(T1、T2、T3(。为 T1 添加的所有列将彼此相邻放置,对于其他 2 种类型也是如此。如果我在我的数据上下文中维护一个布尔值列表,我将不得不做很多工作来维护列表中的正确值,因为在特定位置添加和删除列。例如,假设用户删除了位置 6 处先前添加的列,那么我将不得不遍历网格的所有行并通过删除已删除列的 bool 值来重新排列列表。如果在两者之间的某个位置插入新列,则需要相同的列。它可能也不利于性能。

问题是在 DataGrid 中,实际的复选框控件是"重用"的。与其更改复选框控件,不如更改基础数据(添加到 person 类中(。

然后像这样绑定:

<DataGridCheckBoxColumn Header="Column-1" IsChecked="{Binding IsCheckedColumn1}"/>

然后,您实际上会像这样更改基础数据:

private void userGrid_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var selectedItems = userGrid.SelectedItems;
foreach (var item as Person in selectedItems)
{
item.IsCheckedColumn1 = true;
}
userGrid.UnselectAllCells();
}

您还需要为人员类实现INotifyPropertyChanged

编辑以回答评论

如果您有可变数量的复选框,则可以使用List<bool>

更改值,如下所示:

item.IsChecked[0] = true;

您可以像这样绑定到列表:

<DataGridCheckBoxColumn Header="Column-1" IsChecked="{Binding IsChecked[0]}"/>

最新更新