Как выбрать все флажки столбца по заголовку DataGrid в WPF DataGrid

У меня есть DataGrid с одним CheckBoxColumn. В заголовке этого CheckBoxColumn я добавил флажок, чтобы выбрать все флажки этой строки Datagrid.

Как я могу этого достичь?

мой код XAML для WPF dataGrid:

    <DataGrid AutoGenerateColumns="False" CanUserAddRows="False"  Grid.RowSpan="2" Height="130" HorizontalAlignment="Left" IsReadOnly="False" Margin="189,340,0,0" Name="dgCandidate" TabIndex="7" VerticalAlignment="Top" Width="466" Grid.Row="1" >
        <DataGrid.Columns>
            <DataGridTextColumn x:Name="colCandidateID" Binding="{Binding CandidateID}" Header="SlNo" MinWidth="20" IsReadOnly="True" />
            <DataGridTextColumn x:Name="colRegistraion" Binding="{Binding RegisterNo}" Header="Reg. No." IsReadOnly="True"  />
            <DataGridTextColumn x:Name="colCandidate" Binding="{Binding CandidateName}" Header="Name" MinWidth="250" IsReadOnly="True"  />

            <DataGridTemplateColumn>
                <DataGridTemplateColumn.Header>
                    <CheckBox Name="chkSelectAll" Checked="chkSelectAll_Checked" Unchecked="chkSelectAll_Unchecked"></CheckBox>
                </DataGridTemplateColumn.Header>
                <DataGridTemplateColumn.CellTemplate >
                    <DataTemplate >
                        <CheckBox x:Name="colchkSelect1" Checked="colchkSelect1_Checked" Unchecked="colchkSelect1_Unchecked" ></CheckBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>

        </DataGrid.Columns>

    </DataGrid>

4 ответов


преобразуйте свой класс-кандидат во что-то вроде этого:

public class Candidate : DependencyObject
{
    //CandidateID Dependency Property
    public int CandidateID
    {
        get { return (int)GetValue(CandidateIDProperty); }
        set { SetValue(CandidateIDProperty, value); }
    }
    public static readonly DependencyProperty CandidateIDProperty =
        DependencyProperty.Register("CandidateID", typeof(int), typeof(Candidate), new UIPropertyMetadata(0));
    //RegisterNo Dependency Property
    public int RegisterNo
    {
        get { return (int)GetValue(RegisterNoProperty); }
        set { SetValue(RegisterNoProperty, value); }
    }
    public static readonly DependencyProperty RegisterNoProperty =
        DependencyProperty.Register("RegisterNo", typeof(int), typeof(Candidate), new UIPropertyMetadata(0));
    //CandidateName Dependency Property
    public string CandidateName
    {
        get { return (string)GetValue(CandidateNameProperty); }
        set { SetValue(CandidateNameProperty, value); }
    }
    public static readonly DependencyProperty CandidateNameProperty =
        DependencyProperty.Register("CandidateName", typeof(string), typeof(Candidate), new UIPropertyMetadata(""));
    //BooleanFlag Dependency Property
    public bool BooleanFlag
    {
        get { return (bool)GetValue(BooleanFlagProperty); }
        set { SetValue(BooleanFlagProperty, value); }
    }
    public static readonly DependencyProperty BooleanFlagProperty =
        DependencyProperty.Register("BooleanFlag", typeof(bool), typeof(Candidate), new UIPropertyMetadata(false));
}

в MainWindow.язык XAML:

<DataGrid ItemsSource="{Binding CandidateList}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Id" Binding="{Binding CandidateID}"/>
        <DataGridTextColumn Header="RegNr" Binding="{Binding RegisterNo}"/>
        <DataGridTextColumn Header="Name" Binding="{Binding CandidateName}"/>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.Header>
                <CheckBox Checked="CheckBox_Checked" Unchecked="CheckBox_Checked"></CheckBox>
            </DataGridTemplateColumn.Header>
            <DataGridTemplateColumn.CellTemplate >
                <DataTemplate>
                    <CheckBox IsChecked="{Binding BooleanFlag}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

в MainWindow.код XAML.cs:

    public MainWindow()
    {
        DataContext = this;
        CandidateList.Add(new Candidate()
        {
            CandidateID = 1,
            CandidateName = "Jack",
            RegisterNo = 123,
            BooleanFlag = true
        });
        CandidateList.Add(new Candidate()
        {
            CandidateID = 2,
            CandidateName = "Jim",
            RegisterNo = 234,
            BooleanFlag = false
        });
        InitializeComponent();
    }
    //List Observable Collection
    private ObservableCollection<Candidate> _candidateList = new ObservableCollection<Candidate>();
    public ObservableCollection<Candidate> CandidateList { get { return _candidateList; } }
    private void CheckBox_Checked(object sender, RoutedEventArgs e)
    {
        foreach (var item in CandidateList)
        {
            item.BooleanFlag = true;
        }
    }
    private void UnheckBox_Checked(object sender, RoutedEventArgs e)
    {
        foreach (var item in CandidateList)
        {
            item.BooleanFlag = false;
        }
    }

строго говоря, модель не должна знать о представлении, и поэтому решение, предложенное blindmeis, где изменение модели обновляет каждую строку в datagrid, нарушает шаблон проектирования MVVM/Presentation. Помните, что в MVVM поток зависимостей-View - > ViewModel - > Model, поэтому, если вы ссылаетесь на элементы управления в своей модели представления (или код управления), то вы эффективно нарушили шаблон, и вы, вероятно, столкнетесь с проблемами дальше по пути.


я добавил флажок, чтобы выбрать все флажки в строке Datagrid

Если вы имеете в виду флажок " все " в datagrid колонки, тогда я бы сказал: просто обновите свою коллекцию itemssource с помощью checked / unchecked.

public bool SelectAll
{
  get{return this._selectAll;}
  set
  {
     this._selectAll = value;
     this.MyItemsSourceCollection.ForEach(x=>x.MyRowCheckProperty=value);
     this.OnPropertyChanged("SelectAll");
  }
}

xaml

        <DataGridTemplateColumn>
            <DataGridTemplateColumn.Header>
                <CheckBox isChecked="{Binding SelectAll}"></CheckBox>
            </DataGridTemplateColumn.Header>
            <DataGridTemplateColumn.CellTemplate >
                <DataTemplate >
                    <CheckBox IsChecked="{Binding MyRowCheckProperty}"></CheckBox>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

Я не знаю, правильны ли привязки xaml, но я надеюсь, что вы видите мое намерение


оказывается, что это довольно трудно получить право, чем можно было бы надеяться.

первая проблема заключается в том, что вы не можете просто привязать модель представления к заголовку столбца, потому что у нее нет модели представления в качестве контекста данных, поэтому вам нужен прокси-сервер привязки для правильного маршрутизации привязки к модели представления.

public class BindingProxy : Freezable
{
    public static readonly DependencyProperty DataProperty = DependencyProperty.Register(
        "Data", 
        typeof(object), 
        typeof(BindingProxy),
        new UIPropertyMetadata(null));

    public object Data
    {
        get { return this.GetValue(DataProperty); }
        set { this.SetValue(DataProperty, value); }
    }

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }
}

Теперь создайте прокси-сервер привязки в ресурсах вашей сетки данных:

<DataGrid.Resources>
    <aon:BindingProxy
        x:Key="DataContextProxy"
        Data="{Binding}" />
</DataGrid.Resources>

столбец должен быть определен as:

<DataGridTemplateColumn>
    <DataGridTemplateColumn.HeaderTemplate>
        <DataTemplate>
            <CheckBox
                Command="{Binding
                    Data.SelectAllCommand,
                    Source={StaticResource DataContextProxy}}"
                IsChecked="{Binding
                    Data.AreAllSelected,
                    Mode=OneWay,
                    Source={StaticResource DataContextProxy},
                    UpdateSourceTrigger=PropertyChanged}"
                IsThreeState="True" />
        </DataTemplate>
    </DataGridTemplateColumn.HeaderTemplate>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <CheckBox
                IsChecked="{Binding
                    Path=IsSelected,
                    UpdateSourceTrigger=PropertyChanged}" />
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

обратите внимание, что должна быть привязка к обоим флажкам IsChecked свойства зависимостей, и его Command собственность и IsChecked привязка OneWay. The IsChecked привязка получает флажок для отображения текущего состояния элементов и Command привязка выполняет отбор. Вы нужны оба.

теперь в модели вида:

public bool? AreAllSelected
{
    get
    {
        return this.Items.All(candidate => candidate.IsSelected)
        ? true
        : this.Items.All(candidate => !candidate.IsSelected)
            ? (bool?)false
            : null;
    }

    set
    {
        if (value != null)
        {
            foreach (var item in this.Items)
            {
                item.IsSelected = value.Value;
            }
        }

        this.RaisePropertyChanged();
    }
}

и SelectAllCommand свойство является реализацией ICommand здесь Execute способ есть:

public void Execute(object parameter)
{
    var allSelected = this.AreAllSelected;

    switch (allSelected)
    {
        case true:
            this.AreAllSelected = false;
            break;
        case false:
        case null:
            this.AreAllSelected = true;
            break;
    }
}

наконец, ваши модели просмотра элементов строки (т. е. вещи в Items) нужно поднимать PropertyChanged на модели основного вида каждый раз значение IsSelected изменения. Как вы делаете это в значительной степени зависит от вас.