WPF Datagrid Header数据绑定,表头复选框实现全选、全否、部分选中,根据条目动态变化


制作一个表头为CheckBox可全选、全不选的列表,且可根据条目自动调整CheckBox的状态(选中、不选、部分选中)。

本来是想用DataGrid做一个CheckBox的列用于勾选其中的某些行,当时做出来之后想着添加一个全选、全否的功能。做两个按钮觉得太丑,就想着在标题栏做一个CheckBox实现此功能。开始不用会用模板,网上查了些资料可以用以下方式实现:

1、通过DatGridTemplateColumn修改表头模板实现

                <DataGridTemplateColumn>
                    <DataGridTemplateColumn.HeaderTemplate>
                        <DataTemplate>
                            <CheckBox x:Name="CkB1" Click="Button_Click_2_Header" Tag="{Binding A4, Mode=TwoWay}" IsThreeState="True"></CheckBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.HeaderTemplate>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding A4, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Click="Button_Click_2_Body"></CheckBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
2、根据DataGridCheckBoxColumn修改表头模板实现
                <DataGridCheckBoxColumn >
                    <DataGridCheckBoxColumn.HeaderTemplate >
                        <DataTemplate>
                            <CheckBox Click="CheckBox_Click_3_Header"></CheckBox>
                        </DataTemplate>
                    </DataGridCheckBoxColumn.HeaderTemplate>

                    <DataGridCheckBoxColumn.ElementStyle>
                        <Style TargetType="CheckBox">
                            <Setter Property="IsChecked" Value="{Binding A5}"></Setter>
                        </Style>
                    </DataGridCheckBoxColumn.ElementStyle>
                </DataGridCheckBoxColumn>

实现显示之后可根据Click、Checked、UnCkecked事件控制全选与全否。

但是如何实现表头状态的自动调整没啥思路,网上搜了一下资料:

以下两种实现方式:

1、给表头控件添加空间名称,使用时根据名称找到控件,再根据动作调整控件状态。

如查找“CKB1“控件,通过VisualTreeHelper

        CheckBox cb = GetVisualChild<CheckBox>(this.TestDG, v => v.Name == "CkB1");
        public T GetVisualChild<T>(DependencyObject parent, Func<T, bool> predicate) where T : Visual
        {
            int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < numVisuals; i++)
            {
                DependencyObject v = (DependencyObject)VisualTreeHelper.GetChild(parent, i);
                T child = v as T;
                if (child == null)
                {
                    child = GetVisualChild<T>(v, predicate);
                    if (child != null)
                    {
                        return child;
                    }
                }
                else
                {
                    if (predicate(child))
                    {
                        return child;
                    }
                }
            }
            return null;
        }

2、直接绑定数据,网上没找到源码,分享一下其中一种实现形式:

a,使用DataGridCheckBoxColumn

<DataGridCheckBoxColumn>
                    <DataGridCheckBoxColumn.HeaderTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding Path=DataContext.IsSelectedAll,Mode=TwoWay,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, UpdateSourceTrigger=PropertyChanged}"
                                      Click="DGHeaderCheckBoxClick"
                                      IsThreeState="True"></CheckBox>
                        </DataTemplate>
                    </DataGridCheckBoxColumn.HeaderTemplate>
                    <DataGridCheckBoxColumn.ElementStyle>
                        <Style TargetType="CheckBox">
                            <Setter Property="IsChecked" Value="{Binding A5,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></Setter>
                            <EventSetter Event="CheckBox.Click" Handler="DGRowCheckBoxClick"></EventSetter>
                        </Style>
                    </DataGridCheckBoxColumn.ElementStyle>
                </DataGridCheckBoxColumn>

b、使用DataGridTemplateColumn

<DataGridTemplateColumn>
                    <DataGridTemplateColumn.HeaderTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding Path=DataContext.IsSelectedAll,Mode=TwoWay,RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, UpdateSourceTrigger=PropertyChanged}"
                                      Click="DGHeaderCheckBoxClick"
                                      IsThreeState="True"></CheckBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.HeaderTemplate>
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding A5,Mode=TwoWay,  UpdateSourceTrigger=PropertyChanged}" Click="DGRowCheckBoxClick"></CheckBox>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>

绑定的类

public class DataT : DependencyObject
    {
        public bool? IsSelectedAll
        {
            get { return ( bool?)GetValue(IsSelectedAllProperty); }
            set { SetValue(IsSelectedAllProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsSelectedAll.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsSelectedAllProperty =
            DependencyProperty.Register("IsSelectedAll", typeof( bool?), typeof(DataT));


        public string Name2
        {
            get { return (string)GetValue(Name2Property); }
            set { SetValue(Name2Property, value); }
        }

        // Using a DependencyProperty as the backing store for Name2.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Name2Property =
            DependencyProperty.Register("Name2", typeof(string), typeof(DataT));        


        public ObservableCollection<Data> Datas1
        {
            get { return (ObservableCollection<Data>)GetValue(Datas1Property); }
            set { SetValue(Datas1Property, value); }
        }

        // Using a DependencyProperty as the backing store for Datas1.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty Datas1Property =
            DependencyProperty.Register("Datas1", typeof(ObservableCollection<Data>), typeof(DataT));
        
    }
public class Data : DependencyObject
    {
        。。。。。。
        public bool A5
        {
            get { return (bool)GetValue(A5Property); }
            set { SetValue(A5Property, value); }
        }

        // Using a DependencyProperty as the backing store for A5.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty A5Property =
            DependencyProperty.Register("A5", typeof(bool), typeof(Data));


    }

绑定方式

            datat.Datas1 = new ObservableCollection<Data>()
            {
                new Data(){ A1 = "A1", A2 = true, A3 = "A3", A4 = false, A5 = true },
                new Data(){ A1 = "A1", A2 = true, A3 = "A3", A4 = false, A5 = true }
            };
            datat.IsSelectedAll = true;
            datat.Name2 = "ASD";
            this.TestDG2.DataContext = datat;  

点击表头和行对应的响应函数

private void DGHeaderCheckBoxClick(object sender, RoutedEventArgs e)
        {
            CheckBox cb = sender as CheckBox;
            if (null != cb)
            {
                if (cb.IsChecked == true)
                {
                    //全选
                    foreach (var item in datat.Datas1)
                    {
                        item.A5 = true;
                    }
            
                }
                if (cb.IsChecked == false)
                {
                    //全选
                    foreach (var item in datat.Datas1)
                    {
                        item.A5 = false;
                    }

                }
            }
        }

        private void DGRowCheckBoxClick(object sender, RoutedEventArgs e)
        {
            if (datat.Datas1.FirstOrDefault(item => item.A5 == false) != null && datat.Datas1.FirstOrDefault(item => item.A5 == true) != null)
            {
                datat.IsSelectedAll = null;
            }
            else if (datat.Datas1.FirstOrDefault(item => item.A5 == false) == null)
            {
                datat.IsSelectedAll = true;
            }
            else
            {
                datat.IsSelectedAll = false;
            }
        }




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章