向下拖动鼠标左键上的多个复选框并拖入WPF

时间:2018-10-03 18:24:18

标签: wpf c#-4.0 wpfdatagrid

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

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

我尝试过的事情

    通过获取SelectedCells集合
  1. 切换复选框
  2. 通过在VisualTreeHelper的选择的蓝色框下获得复选框来进行切换
  3. 通过获取行索引和列索引来循环拖动拖动区域下的行和列

所有方法导致相同的行为。 我想了解这种方法的错误所在。我用于第一种方法的代码后面的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; }
}

image of result for better understanding

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

编辑:

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

1 个答案:

答案 0 :(得分:0)

问题在于,在DataGrid中,实际的复选框控件已被“重用”。而不是更改复选框控件,您应该更改基础数据(添加到您的人员类中)。

然后像这样绑定:

<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]}"/>