WPF Seleccione todas las casillas de verificación en un DataGrid

 C Programming >> Programación C >  >> Tags >> WPF
WPF Seleccione todas las casillas de verificación en un DataGrid

TLDR; Esto es lo que quieres, código a continuación:

El lugar adecuado para hacer esto sería en su ViewModel. Su CheckBox puede tener tres estados, todos los cuales desea utilizar:

  1. Marcado:todos los elementos están marcados
  2. Desmarcado:ningún elemento está marcado
  3. Indeterminado:algunos elementos están marcados, otros no

Querrá actualizar el CheckBox cada vez que un elemento esté marcado/desmarcado y actualizar todos los elementos cada vez que se cambie el CheckBox; implementar esta única forma dejará el CheckBox en un estado no válido, lo que podría tener un impacto negativo en la experiencia del usuario. Mi sugerencia:ir hasta el final e implementarlo correctamente. Para hacer esto, debe saber qué causó el cambio:el CheckBox de una entrada o el CheckBox en el encabezado.

Así es como lo haría:

Primero necesita un ViewModel para sus artículos, he usado uno muy simplificado aquí que solo contiene el IsChecked propiedad.

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

Su ViewModel principal tendrá una colección de todos los elementos. Siempre que un elemento IsChecked cambia la propiedad, tendrá que comprobar si todas los elementos están marcados/desmarcados y actualizan el CheckBox en el encabezado (o más bien el valor de su fuente de datos).

public class ViewModel : INotifyPropertyChanged
{
    public List<Entry> Entries
    {
        get => _entries;
        set
        {
            if (Equals(value, _entries)) return;
            _entries = value;
            OnPropertyChanged();
        }
    }

    public ViewModel()
    {
        // Just some demo data
        Entries = new List<Entry>
        {
            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<Entry> _entries;
    private bool? _allSelected;
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

XAML de demostración:

<DataGrid ItemsSource="{Binding Entries}" AutoGenerateColumns="False" IsReadOnly="False" CanUserAddRows="False">
    <DataGrid.Columns>
        <DataGridCheckBoxColumn Binding="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}">
            <DataGridCheckBoxColumn.HeaderTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=local:MainWindow}, Path=ViewModel.AllSelected}">Select All</CheckBox>
                </DataTemplate>
            </DataGridCheckBoxColumn.HeaderTemplate>
        </DataGridCheckBoxColumn>
    </DataGrid.Columns>
</DataGrid>

Lo que hace en su ejemplo es iterar a través del elemento de datos, no a través de los controles (supongo que no tiene controles como ItemsSource).
En el enlace que ha publicado YourClass es la clase de ViewModel, objeto de datos para la fila de la cuadrícula.

Este debería funcionar con cambios de código mínimos de su parte (pero preferiría manejarlo en ViewModel con algo como CheckUncheckCommand + enlace de IsChecked al CommandParameter ):

<DataGridCheckBoxColumn x:Name="col0" HeaderStyle="{StaticResource ColumnHeaderGripperStyle}" DisplayIndex="0">

private void CheckUnCheckAll(object sender, RoutedEventArgs e)
{
    var chkSelectAll = sender as CheckBox;
    var firstCol = dgUsers.Columns.OfType<DataGridCheckBoxColumn>().FirstOrDefault(c => c.DisplayIndex == 0);
    if (chkSelectAll == null || firstCol == null || dgUsers?.Items == null)
    {
        return;
    }
    foreach (var item in dgUsers.Items)
    {
        var chBx = firstCol.GetCellContent(item) as CheckBox;
        if (chBx == null)
        {
            continue;
        }
        chBx.IsChecked = chkSelectAll.IsChecked;
    }
}

No