17 Mar 2011

Checkbox to Select in WPF Datagrid

No Comments WPF

There are several datagrids available for WPF, but in my experience the best free one is the one included in .NET 4 (formerly the WPF toolkit). A fairly common task which I use in dialogs is using a checkbox to allow selection of items. This isn’t as trivial as it appears with the WPF datagrid, but it is possible.

The first thing you need is an extended DataGrid control which includes a handler for the OnPreviewMouseLeftButtonDown event which listens for mouse clicks, then if the clicked cell contains a checkbox, places the cell in edit mode and toggles the checkbox.

public class CheckboxDataGrid : DataGrid
{
    public CheckboxDataGrid()
    {
        EventManager.RegisterClassHandler(typeof(DataGridCell),
            DataGridCell.PreviewMouseLeftButtonDownEvent,
            new RoutedEventHandler(this.OnPreviewMouseLeftButtonDown));
    }
 
 
    private void OnPreviewMouseLeftButtonDown(object sender, RoutedEventArgs e)
    {
        DataGridCell cell = sender as DataGridCell;
        if (cell != null && !cell.IsEditing && !cell.IsReadOnly)
        {
 
                var parentRow = cell.Parent as DataGridRow;
                if (parentRow != null)
                {
                    SelectedIndex = parentRow.GetIndex();
                }
                CurrentCell = new DataGridCellInfo(cell);
                BeginEdit(e);
         DependencyObject obj = FindVisualChild<CheckBox>(cell);
            if (obj != null) {
                System.Windows.Controls.CheckBox cb = (System.Windows.Controls.CheckBox)obj;
                cb.Focus();
                cb.IsChecked = !cb.IsChecked;
            }
        }
    }
    public static TChild FindVisualChild<TChild>(DependencyObject obj) where TChild : DependencyObject {
        for(int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++) {
            DependencyObject child = VisualTreeHelper.GetChild(obj, i);
            if(child != null && child is TChild) {
                return (TChild)child;
            } else {
                TChild childOfChild = FindVisualChild<TChild>(child);
                if(childOfChild != null)
                    return childOfChild;
            }
        }
        return null;
    }
}
<locui:CheckboxDataGrid x:Name="dgCategories" DockPanel.Dock="Bottom" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" VerticalAlignment="Stretch" SelectionMode="Single" 
    SelectionUnit="FullRow" CanUserSortColumns="True" EnableRowVirtualization="True" GridLinesVisibility="Horizontal"
    ItemsSource="{Binding Path=Categories,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" HeadersVisibility="Column" 
    ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.CanContentScroll="True" SelectedValuePath="CategoryID">
    <DataGrid.Columns>
        <DataGridTemplateColumn Width="18">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding IsSelected}" IsEnabled="False"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding IsSelected,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Checked="chkCategories_CheckedStateChanged" Unchecked="chkCategories_CheckedStateChanged"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>

IsSelected is a property of the objects to which the grid is bound.

While this gets you 99% of the way there, the only situation it doesn’t work in is uopdating the last checked item. Eg: If a row is checked, then a button is clicked which closes the dialog, the item won’t be updated because the cell is still in edit mode. To update the item instantly, the handler for the checkbox’s Checked and Unchecked event also toggles the selection.

private void chkCategories_CheckedStateChanged(object sender, RoutedEventArgs e)
{
    var cat = (dgCategories.CurrentItem as SelectableCategory);
    var checkBox = sender as CheckBox;
    if (cat != null && checkBox != null)
    {
        cat.IsSelected = checkBox.IsChecked == true;
    }
}
Tags: , , ,
written by
The author didn‘t add any Information to his profile yet.
No Responses to “Checkbox to Select in WPF Datagrid”

Leave a Reply