views:

15

answers:

1

I've got a WPF toolkit datagrid with virtualization turned on. Each row has a check box bound to a bool in the underlying model.

The check boxes (in addition to the data binding) also have Checked and Unchecked handlers (!) to allow checking multiple items at once if you've click one with multiple lines selected.

Here's the xaml:

<Controls:DataGrid ItemsSource="{Binding UnderlyingData}"
                   AutoGenerateColumns="False"
                   HeadersVisibility="Column">

  <Controls:DataGrid.Columns>
    <Controls:DataGridTemplateColumn Header="Use?" SortMemberPath="Use">
      <Controls:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
          <CheckBox Style="{StaticResource DataGridCheckBoxStyle}" IsChecked="{Binding Spike}"
                    Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked" />
        </DataTemplate>
      </Controls:DataGridTemplateColumn.CellTemplate>
    </Controls:DataGridTemplateColumn>              
  </Controls:DataGrid.Columns>
</Controls:DataGrid>

And the Checked/Unchecked handlers:

private void CheckBox_Checked(object sender, RoutedEventArgs e)
{
    if (!processingMultipleRows)
    {
        UpdateAllSelected(e.OriginalSource as ToggleButton);
        e.Handled = true;
    }
}

private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
{
    if (!processingMultipleRows)
    {
        UpdateAllSelected(e.OriginalSource as ToggleButton);
        e.Handled = true;
    }
}

private void UpdateAllSelected(ToggleButton checkBox)
{
    processingMultipleRows= true;
    var include = checkBox.IsChecked ?? false;
    tickBoxSelector.ApplyToAllSelected<RowViewModel>(checkBox, p => p.Use = include);
    ViewModel.ProcessUseStateChange();
    processingMultipleRows= false;
}

This code works in every way except one. ViewModel.ProcessUseStateChange() is fairly slow and is currently called once whenever you toggle one or more CheckBoxes. Which is fine, but it's also called once for each new line appearing in view when you scroll the datagrid, since virtualization means new rows have to be created and their Check state must be set.

Is there a cunning way to determine whether Checked is being called in response to a mouse click or an instantiation of a new row due to virtualization?

A: 

The solution I found in the end was to handle the Click event, rather than Checked/Unchecked, this simplified things hugely:

<Controls:DataGrid ItemsSource="{Binding UnderlyingData}"
                   AutoGenerateColumns="False"
                   HeadersVisibility="Column">

  <Controls:DataGrid.Columns>
    <Controls:DataGridTemplateColumn Header="Use?" SortMemberPath="Use">
      <Controls:DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
          <CheckBox Style="{StaticResource DataGridCheckBoxStyle}" IsChecked="{Binding Spike}"
                    Click="CheckBox_Clicked"/>
        </DataTemplate>
      </Controls:DataGridTemplateColumn.CellTemplate>
    </Controls:DataGridTemplateColumn>              
  </Controls:DataGrid.Columns>
</Controls:DataGrid>

and:

private void CheckBox_Clicked(object sender, RoutedEventArgs e)
{
    UpdateAllSelected(e.OriginalSource as ToggleButton);
    e.Handled = true;
}

private void UpdateAllSelected(ToggleButton checkBox)
{
    var include = checkBox.IsChecked ?? false;
    tickBoxSelector.ApplyToAllSelected<RowViewModel>(checkBox, p => p.Use = include);
    ViewModel.ProcessUseStateChange();
}
Jackson Pope