使用DataGrid WPF的复选框

Raj*_*eja 5 wpf mvvm wpf-controls wpfdatagrid wpf-4.0

我正在尝试使用MVVM在WPF 4.0中创建一个DataGrid ...

所需功能 -

  1. 多个 - 使用复选框选择行(单击)
  2. 选中全部复选框以检查数据网格中的所有复选框

像这样的东西 -

在此输入图像描述

已经2天了,我无法弄清楚如何有效地解决问题.

一个工作的例子就是我现在所需要的......

如果有人有一个可行的解决方案与我分享,我将非常感激...

N请不要告诉我google这个东西,因为没有一件事对我有用......

更新 -

  1. 我正在使用AutoGeneration of Columns
  2. 我不想在我的模型中添加"IsSelected"或任何此类属性.
  3. 我只是面临两个问题 -

首先,"选择所有"功能,即选中复选框上的所有复选框,单击列标题中存在的复选框...(我可以选择和取消选择数据网格但不能勾选/取消勾选复选框)

其次,鼠标点击多次选择而不按住Ctrl键..

Rac*_*hel 19

当您使用MVVM时,您必须了解什么是数据以及什么是严格的UI.

SelectedItems将成为数据的一部分,还是仅仅是您的UI?

如果它是数据的一部分,那么IsSelected你的数据模型上应该有一个属性,即使这意味着扩展数据类以包含IsSelected属性,或创建仅包含bool IsSelected和的包装类object MyDataItem.第一个选项可能是首选,因为您可以保留AutoGenerateColumns="True",并且它使列绑定更简单.

然后,您只需将您绑定DataGridRow.SelectedItemIsSelected数据项的属性:

<Style TargetType="{x:Type DataGridRow}">
    <Setter Property="IsSelected" Value="{Binding IsSelected}" />
</Style>
Run Code Online (Sandbox Code Playgroud)

但是,如果您SelectedItems只是用于UI,或者您在此实例中由于某种原因打破MVVM模式,那么您可以创建未绑定CheckBox并使用一些代码来确保CheckBox正确同步到SelectedItem.

我做了一个快速的示例应用程序,这是我的代码看起来像:

首先,我刚刚CheckBox使用a 将未绑定列添加到列列表中DataGridTemplateColumn.这将在AutoGenerateColumns列列表之前添加.

<DataGrid x:Name="TestDataGrid" ItemsSource="{Binding Test}" 
          SelectionMode="Extended" CanUserAddRows="False"
          PreviewMouseLeftButtonDown="TestDataGrid_PreviewMouseLeftButtonDown_1">
    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox x:Name="TestCheckBox"
                              PreviewMouseLeftButtonDown="CheckBox_PreviewMouseLeftButtonDown" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>
Run Code Online (Sandbox Code Playgroud)

其次,我添加了一个PreviewMouseDown事件,CheckBox使其设置IsSelected行的属性.

private void CheckBox_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var chk = (CheckBox)sender;
    var row = VisualTreeHelpers.FindAncestor<DataGridRow>(chk);
    var newValue = !chk.IsChecked.GetValueOrDefault();

    row.IsSelected = newValue;
    chk.IsChecked = newValue;

    // Mark event as handled so that the default 
    // DataGridPreviewMouseDown doesn't handle the event
    e.Handled = true;
}
Run Code Online (Sandbox Code Playgroud)

它需要导航VisualTree以找到DataGridRow与单击相关联的CheckBox选择它,并使生活更轻松我使用我在博客上的一些自定义VisualTreeHelpers来查找DataGridRow.您可以使用相同的代码,也可以创建自己的搜索方法VisualTree.

最后,如果用户点击了除此之外的任何地方CheckBox,我们想要禁用默认DataGrid选择事件.这样可以确保IsSelected只有在单击时才会更改该值CheckBox.

有多种方法可以在不同级别禁用选择,但为了简化生活我只是禁用了DataGrid.PreviewMouseLeftButtonDown事件,如果用户没有点击CheckBox.

private void TestDataGrid_PreviewMouseLeftButtonDown_1(object sender, MouseButtonEventArgs e)
{
    var chk = VisualTreeHelpers.FindAncestor<CheckBox>((DependencyObject)e.OriginalSource, "TestCheckBox");

    if (chk == null)
        e.Handled = true;
}
Run Code Online (Sandbox Code Playgroud)

我再次使用我的自定义VisualTreeHelpers导航可视化树,并查看是否单击了CheckBox,如果用户点击了除此之外的任何位置,则取消该事件CheckBox.

至于加入的你的第二请求CheckBoxSelectAllUnselectAll项目,这将再次成为依赖,如果你的选择是UI或数据的一部分.

如果它的用户界面的一部分,只需添加一个CheckBoxDataGridTemplateColumn.HeaderTemplate,并单击时,遍历DataGrid.Rows,找到CheckBox在第一列,并选中或取消选中它.

如果它是数据的一部分你仍然可以做同样的事情(只设置绑定值DataGrid.Items而不是CheckBox.IsChecked来自DataGrid.Rows),或者你可以像Adolfo Perez建议的那样,并将它绑定到一个属性上ViewModel.

  • 真棒雷切尔..真的很棒..稍微调整了代码以优化d工作...否则它真的很整洁... (2认同)