none
DataGrid Header Template Binding question RRS feed

  • Question

  • Hi there,

    I have a DataGrid which binds to a List<> on a ViewModel. The first column is CheckBox column which binds to a property on the object in the List<>. In the header template of the checkbox column, I added another checkbox to allow the user, to select all the items in the grid. The checkbox is being displayed in the header, but the OnPropertyChanged event does not fire when the IsChecked value for the checkbox is changed. The checkbox in the header's IsChecked property is bound to a property on the ViewModel called AllSelected. What am I missing because this does not work.

    <DataGrid Margin="0,75,0,0" Name="dgAppointmentMessages" ItemsSource="{Binding Messages}" AutoGenerateColumns="False" IsReadOnly="True" SelectedItem="{Binding SelectedMessage}">
                    <DataGrid.Columns>
                        <DataGridTemplateColumn>
                            <DataGridTemplateColumn.HeaderTemplate>
                                <DataTemplate>
                                    <CheckBox Margin="6,0" IsChecked="{Binding AllSelected, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}" Template="{StaticResource ResourceKey=CheckBoxImageTemplate}" />
                                </DataTemplate>
                            </DataGridTemplateColumn.HeaderTemplate>
                            <DataGridTemplateColumn.CellTemplate>
                                <DataTemplate>
                                    <CheckBox Margin="6,0" IsChecked="{Binding SendMessage, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}" Template="{StaticResource ResourceKey=CheckBoxImageTemplate}" />
                                </DataTemplate>
                            </DataGridTemplateColumn.CellTemplate>
                        </DataGridTemplateColumn>
                        <DataGridTextColumn Header="Official" Binding="{Binding MemberName}" />
                        <DataGridTextColumn Header="Game Date" Binding="{Binding GameDate, StringFormat=\{0:ddd dd MMM yyyy\}}" />
                        <DataGridTextColumn Header="Game Time" Binding="{Binding GameDate, StringFormat=\{0:HH:mm\}}" />
                        <DataGridTextColumn Header="Competition" Binding="{Binding Competition}" />
                        <DataGridTextColumn Header="Venue" Binding="{Binding Venue}" />
                        <DataGridTextColumn Header="Duty" Binding="{Binding Duty}" />
                        <DataGridTextColumn Header="MessageType" Binding="{Binding MessageType}" />
                        <DataGridTextColumn Header="Last Update" Binding="{Binding LastUpdate, StringFormat=\{0:ddd dd MMM yyyy\}}" />
                        <DataGridTextColumn Header="Last Sent" Binding="{Binding LastSent, StringFormat=\{0:ddd dd MMM yyyy\}, TargetNullValue=' - '}" />
                        <DataGridTextColumn Header="Send Count" Binding="{Binding SendCount}" />
                    </DataGrid.Columns>
                </DataGrid>

    That is the completed code for the DataGrid.

    Thanks

    Sunday, July 29, 2012 1:07 PM

Answers

  • The problem with Column HeaderTemplate is it is a generated control part of the DataGrid and does not have direct VisualTree access to the DataGrid's DataContext, so you have to add RelativeSource AncestorType and explicitly refer to the property via the DataContext, as shown below:

     

    MainWindow.xaml

    <Window x:Class="WpfApplication43.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <DataGrid Margin="0,75,0,0" Name="dgAppointmentMessages" ItemsSource="{Binding Messages}" AutoGenerateColumns="False" IsReadOnly="True" SelectedItem="{Binding SelectedMessage}">
                <DataGrid.Columns>
                    <DataGridTemplateColumn>
                        <DataGridTemplateColumn.HeaderTemplate>
                            <DataTemplate>
                                <CheckBox Margin="6,0" IsChecked="{Binding DataContext.AllSelected, RelativeSource={RelativeSource AncestorType=Window}, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}" />
                            </DataTemplate>
                        </DataGridTemplateColumn.HeaderTemplate>
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox Margin="6,0" IsChecked="{Binding SendMessage, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}"  />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTextColumn Header="Official" Binding="{Binding MemberName}" />
                    <DataGridTextColumn Header="Game Date" Binding="{Binding GameDate, StringFormat=\{0:ddd dd MMM yyyy\}}" />
                    <DataGridTextColumn Header="Game Time" Binding="{Binding GameDate, StringFormat=\{0:HH:mm\}}" />
                    <DataGridTextColumn Header="Competition" Binding="{Binding Competition}" />
                    <DataGridTextColumn Header="Venue" Binding="{Binding Venue}" />
                    <DataGridTextColumn Header="Duty" Binding="{Binding Duty}" />
                    <DataGridTextColumn Header="MessageType" Binding="{Binding MessageType}" />
                    <DataGridTextColumn Header="Last Update" Binding="{Binding LastUpdate, StringFormat=\{0:ddd dd MMM yyyy\}}" />
                    <DataGridTextColumn Header="Last Sent" Binding="{Binding LastSent, StringFormat=\{0:ddd dd MMM yyyy\}, TargetNullValue=' - '}" />
                    <DataGridTextColumn Header="Send Count" Binding="{Binding SendCount}" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </Window>
    

    MainWindow.xaml.cs

    using System.Collections.Generic;
    using System.Windows;
    
    namespace WpfApplication43
    {
        public partial class MainWindow : Window
        {
            public List<Message> Messages { get; set; }
    
            bool _AllSelected;
            public bool AllSelected
            {
                get
                {
                    return _AllSelected;
                }
                set
                {
                    if (_AllSelected != value)
                        _AllSelected = value;
                }
            }
    
            public MainWindow()
            {
                InitializeComponent();
                Messages = new List<Message>{ new Message() };
    
                DataContext = this;
            }
        }
    
        public class Message
        {
            public bool SendMessage { get; set; }
        }
    }
    

     

    Put a breakpoint on the setter to confirm.

     

    Regards,
    Pete


    #PEJL

    Sunday, July 29, 2012 7:56 PM
    Moderator