WPF Select all CheckBox in a DataGrid

前端 未结 3 1924
别那么骄傲
别那么骄傲 2020-12-01 13:48

I\'m trying to select all CheckBox in a DataGrid but I didn\'t get any result using this code bellow

This is the function that I\'m calling when the main CheckBox is

3条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-01 14:07

    TLDR; This is what you want, code below:

    The proper place to do this would be in your ViewModel. Your CheckBox can have three states, all of which you want to make use of:

    1. Checked - Every item is checked
    2. Unchecked - No item is checked
    3. Indeterminate - Some items are checked, some are not

    You will want to update the CheckBox whenever an item is checked/unchecked and update all items whenever the CheckBox was changed - implementing this only one way will leave the CheckBox in an invalid state which might have a negative impact on user experience. My suggestion: go all the way and implement it properly. To do this you need to be aware of which caused the change - the CheckBox of an entry or the CheckBox in the header.

    Here is how I would do it:

    First you need a ViewModel for your items, I've used a very simplified one here that only contains the IsChecked property.

    public class Entry : INotifyPropertyChanged
    {
        private bool _isChecked;
    
        public bool IsChecked
        {
            get => _isChecked;
            set
            {
                if (value == _isChecked) return;
                _isChecked = value;
                OnPropertyChanged();
            }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    Your main ViewModel will have a collection of all items. Whenever an item's IsChecked property changes, you'll have to check if all items are checked/unchecked and update the CheckBox in the header (or rather the value of its datasource).

    public class ViewModel : INotifyPropertyChanged
    {
        public List Entries
        {
            get => _entries;
            set
            {
                if (Equals(value, _entries)) return;
                _entries = value;
                OnPropertyChanged();
            }
        }
    
        public ViewModel()
        {
            // Just some demo data
            Entries = new List
            {
                new Entry(),
                new Entry(),
                new Entry(),
                new Entry()
            };
    
            // Make sure to listen to changes. 
            // If you add/remove items, don't forgat to add/remove the event handlers too
            foreach (Entry entry in Entries)
            {
                entry.PropertyChanged += EntryOnPropertyChanged;
            }
        }
    
        private void EntryOnPropertyChanged(object sender, PropertyChangedEventArgs args)
        {
            // Only re-check if the IsChecked property changed
            if(args.PropertyName == nameof(Entry.IsChecked))
                RecheckAllSelected();
        }
    
        private void AllSelectedChanged()
        {
            // Has this change been caused by some other change?
            // return so we don't mess things up
            if (_allSelectedChanging) return;
    
            try
            {
                _allSelectedChanging = true;
    
                // this can of course be simplified
                if (AllSelected == true)
                {
                    foreach (Entry kommune in Entries)
                        kommune.IsChecked = true;
                }
                else if (AllSelected == false)
                {
                    foreach (Entry kommune in Entries)
                        kommune.IsChecked = false;
                }
            }
            finally
            {
                _allSelectedChanging = false;
            }
        }
    
        private void RecheckAllSelected()
        {
            // Has this change been caused by some other change?
            // return so we don't mess things up
            if (_allSelectedChanging) return;
    
            try
            {
                _allSelectedChanging = true;
    
                if (Entries.All(e => e.IsChecked))
                    AllSelected = true;
                else if (Entries.All(e => !e.IsChecked))
                    AllSelected = false;
                else
                    AllSelected = null;
            }
            finally
            {
                _allSelectedChanging = false;
            }
        }
    
        public bool? AllSelected
        {
            get => _allSelected;
            set
            {
                if (value == _allSelected) return;
                _allSelected = value;
    
                // Set all other CheckBoxes
                AllSelectedChanged();
                OnPropertyChanged();
            }
        }
    
        private bool _allSelectedChanging;
        private List _entries;
        private bool? _allSelected;
        public event PropertyChangedEventHandler PropertyChanged;
    
        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    

    Demo XAML:

    
        
            
                
                    
                        Select All
                    
                
            
        
    
    

提交回复
热议问题