wpf中为DataGrid添加checkbox支持多选全选

时间:2022-02-13 19:37:07
项目中用到DataGrid, 需要在第一列添加checkbox, 可以多选、全选。 其中涉及的概念DataTemplate, DataGridCellStyle, DataGridCellControlTemplate,Binding, OnPropertyChanged等。
有下面是实现思路:
1.继承INotifyPropertyChanged接口,实现OnPropertyChanged方法:  public abstract class ViewModelBase : INotifyPropertyChanged
    {
      public event PropertyChangedEventHandler PropertyChanged;
        /// <summary>         /// Raises this object&apos;s PropertyChanged event.         /// </summary>         /// <param name="propertyName">The property that has a new value</param>         protected void OnPropertyChanged(string propertyName)         {             PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)             {                 handler(this, new PropertyChangedEventArgs(propertyName));             }         }
//..................
}
2. 实现viewModel, 添加IsSelected属性, 存储当前多选状态         private bool _isSelected = true;
        public bool IsSelected         {             get { return _isSelected; }
            set             {                 _isSelected = value;                 OnPropertyChanged("IsSelected");             }         }
3.在VM/Model准备好后, 我们接下来开始对DataGrid进行style自定义
4.准备checkbox的DataTemplate:
<DataTemplate x:Key="CheckboxDataTemplate1">           <Grid>           <CheckBox x:Name="_chkSelected"                         Height="16"                         HorizontalAlignment="Center"                         VerticalAlignment="Center"                         Background="{x:Null}"                         VerticalContentAlignment="Center"                         HorizontalContentAlignment="Center"                         Click="_chkSelected_OnClick"                         IsThreeState="False"                         IsChecked="{Binding IsSelected, Mode=OneWay, FallbackValue=True}"                         />           </Grid>         </DataTemplate>
此示例中checkbox只有简单的2种状态, 1)IsChecked属性绑定VM的IsSelected属性; 2)Mode为OneWay是因为我们需求是用户可以多选行然后点击某行头选中多行。此功能在Click事件中遍历当前所有选中的行,然后更改其VM的IsSelected属性。因此不需要TwoWay模式; 3)在Binding中添加了FallbackValue, 此属性指示当binding失败时给出的默认值。此例中因为DataTemplate也应用在列头, 而列头的DataContext和DataGridRow不同; 4)在Click事件处理函数中,判断当前点击的列头还是行头, 更改对应DataContext的IsSelected属性。 如:       private void _chkSelected_OnClick(object sender, RoutedEventArgs e)         {             CheckBox chkSelected = e.OriginalSource as CheckBox;             if (null == chkSelected)             {                 return;             }
            var studyModel = chkSelected.DataContext as StudyModel;
            bool isChecked = chkSelected.IsChecked.HasValue ? chkSelected.IsChecked.Value : true;             FrameworkElement templateParent = chkSelected.TemplatedParent is FrameworkElement                                                   ? (chkSelected.TemplatedParent as FrameworkElement).TemplatedParent as FrameworkElement                                                   : null;
            if (templateParent is DataGridColumnHeader)             {                 MainViewModel mvm = this.DataContext as MainViewModel;                 if (null != mvm)                 {                     foreach (var sm in mvm.StudyList)                     {                         sm.IsSelected = isChecked;                     }                 }             }             else if (templateParent is DataGridCell)             {                 if (null != studyModel && null != this._grdStudyList.SelectedItems && this._grdStudyList.SelectedItems.Contains(studyModel))                 {                     foreach (var otherSelected in this._grdStudyList.SelectedItems.OfType<StudyModel>())                     {                         otherSelected.IsSelected = isChecked;                     }                 }             }         }
     其中MainViewModel为主VM, 其包含一个ObservableCollection<StudyModel> StudyList, 而StudyModel包含IsSelected属性, 二者都实现OnpropertyChanged方法; _grdStudyList为xaml中的DataGrid
5.应用DataTemplate到DataGridColumnHeader和DataGridCell, 如:
      <Style x:Key="DataGridCheckboxColumnHeaderStyle1" TargetType="{x:Type DataGridColumnHeader}">             <Setter Property="ContentTemplate" Value="{DynamicResource CheckboxDataTemplate1}"/>             <Setter Property="HorizontalAlignment" Value="Stretch"/>             <Setter Property="VerticalAlignment" Value="Stretch"/>       </Style>
      <Style x:Key="DataGridCheckboxCellStyle1" TargetType="{x:Type DataGridCell}">               <Setter Property="Padding" Value="20,0"/>                         <Setter Property="ContentTemplate" Value="{DynamicResource CheckboxDataTemplate1}"/>              <Setter Property="Background" Value="#FFC1C1C1"/>                 <Setter Property="BorderBrush" Value="{x:Null}"/>                       <Setter Property="BorderThickness" Value="0"/>                        <Setter Property="Template" Value="{DynamicResource DataGridCheckboxCellControlTemplate1}"/>               <Style.Triggers>                                        <Trigger Property="IsSelected" Value="True">                                                   <Setter Property="Background" Value="#FFC1C1C1"/>                                            <Setter Property="BorderBrush" Value="{x:Null}"/>                                 </Trigger>                    </Style.Triggers>                   </Style>                    
       <ControlTemplate x:Key="DataGridCheckboxCellControlTemplate1" TargetType="{x:Type DataGridCell}">                   <Border
                  BorderBrush="{TemplateBinding BorderBrush}"
                  BorderThickness="{TemplateBinding BorderThickness}"
                  Background="{TemplateBinding Background}"
                  SnapsToDevicePixels="True">                    
                <ContentPresenter                        ContentTemplate="{TemplateBinding ContentTemplate}"
                      Content="{TemplateBinding Content}"
                      ContentStringFormat="{TemplateBinding ContentStringFormat}"
                      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>                
          </Border>        </ControlTemplate>
6.应用CellStyle和HeaderStyle到DataGrid:
      <DataGrid

x:Name="_grdStudyList"
ItemsSource="{Binding StudyList}"
AutoGenerateColumns="False"
FrozenColumnCount="1" Background="#FF999797">
          <DataGrid.Columns>                   
             <DataGridCheckBoxColumn 

x:Name="_dtcSelected"
Header=""
HeaderStyle="{StaticResource DataGridCheckboxColumnHeaderStyle1}"
CellStyle="{StaticResource DataGridCheckboxCellStyle1}"
MinWidth="60" CanUserReorder="False" MaxWidth="60"/>