Saltar al contenido

WPF Seleccionar todo CheckBox en un DataGrid

Solución:

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

Demo de lo que voy a explicar

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. Sin marcar: ningún elemento está marcado
  3. Indeterminado: algunos elementos están marcados, otros no

Querrá actualizar el CheckBox siempre que un elemento esté marcado / desmarcado y actualizar todos los elementos cada vez que se cambie el CheckBox; implementar esto de una sola manera dejará el CheckBox en un estado no válido 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 artículo IsChecked cambios de propiedad, tendrá que comprobar si todos 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 mínimos de código de su lado (pero yo preferiría manejarlo en ViewModel con algo como CheckUncheckCommand + enlace de IsChecked al CommandParameter):

<DataGridCheckBoxColumn x:Name="col0" Header 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;
    }
}
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *