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;
            }
        }




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