views:

228

answers:

1

I'm really hoping someone can help me out here. I have a DataGrid in my program that has a checkbox column. The ItemsSource for the DataGrid is a DataSet loaded programmatically. When I select a couple of items in the DataGrid and then scroll it, I get some very odd behavior. For example, when I check two of the CheckBoxes, it tells me that I have "2 selected", but then if I scroll up or down in the DataGrid, the number changes. If I scroll back to the initial position it goes back to the "2 selected". As odd as it sounds, it seems like it's calling the Checked/Unchecked events when I scroll the box...very odd...

I have the following defined at the top of my code:

private DataSet MyDataSet;
int selected_count = 0;

Then I have the following code in my method to load the information into the DataSet:

MyDataSet = new DataSet();
DataTable tempDataTable = new DataTable();
MyDataSet.Tables.Add(tempDataTable);

DataColumn tempCol = new DataColumn("Checked", typeof(bool));
tempDataTable.Columns.Add(tempCol);

for (int i = 0; i < 50; i++)
{
    DataRow tempRow = tempDataTable.NewRow();
    tempDataTable.Rows.Add(tempRow);
    tempRow["Checked"] = false;
}

MyList.ItemsSource = MyDataSet.Tables[0].DefaultView;

I have the IsChecked property binded to the DataColumn named "Checked" using the following XAML:

<dtgrd:DataGrid x:Name="MyList" AutoGenerateColumns="False" CanUserAddRows="False" CanUserResizeRows="False" HeadersVisibility="Column" SelectionUnit="FullRow" HorizontalGridLinesBrush="#FF688CAF" VerticalGridLinesBrush="#FF688CAF">
    <dtgrd:DataGrid.Columns>
        <dtgrd:DataGridTemplateColumn x:Name="CheckCol" CanUserSort="True" CanUserResize="False">
            <dtgrd:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox Name="MyCheckBox" IsChecked="{Binding Checked}" HorizontalAlignment="Center" VerticalAlignment="Center" Checked="MyCheckBox_Checked" Unchecked="MyCheckBox_Unchecked" />
                </DataTemplate>
            </dtgrd:DataGridTemplateColumn.CellTemplate>
        </dtgrd:DataGridTemplateColumn>
    </dtgrd:DataGrid.Columns>
</dtgrd:DataGrid>

Then, I have the following events that are called by checking/unchecking one of the checkboxes:

private void MyCheckBox_Checked(object sender, RoutedEventArgs e)
{
    selected_count++;
    TxtSelectedCount.Text = "" + selected_count + " selected";
}

private void MyCheckBox_Unchecked(object sender, RoutedEventArgs e)
{
    selected_count--;
    TxtSelectedCount.Text = "" + selected_count + " selected";
}

I have also tried other things, but get different bugs. For example, I removed the Binding from the XAML code and tried to set it programmatically using the following Checked/Uncheck events:

private void MyCheckBox_Checked(object sender, RoutedEventArgs e)
{
    DataRow tempRow = MyDataSet.Tables[0].Rows[MyList.Items.IndexOf(MyList.SelectedItems[0])];
    tempRow["Checked"] = true;

    selected_count++;
    TxtSelectedCount.Text = "" + selected_count + " selected";
}

private void MyCheckBox_Unchecked(object sender, RoutedEventArgs e)
{
    DataRow tempRow = MyDataSet.Tables[0].Rows[MyList.Items.IndexOf(MyList.SelectedItems[0])];
    tempRow["Checked"] = false;

    selected_count--;
    TxtSelectedCount.Text = "" + selected_count + " selected";
}

When I use that code, the number of checked items stays the same, but the actual checks move around to different items while I'm scrolling.

I honestly have no clue what's going on, but it's very frustrating! Any help would be GREATLY appreciated!

+2  A: 

You're running into item container recycling. See http://blogs.msdn.com/b/vinsibal/archive/2008/05/14/recycling-that-item-container.aspx. WPF is re-using the row objects as you scroll, and you're seeing the Checked and Unchecked events fire as it binds to a different row.

If you want to stick with your current solution, you can just disable item container recycling by adding VirtualizingStackPanel.VirtualizationMode="Standard" to your dtgrd:DataGrid element. You could also disable virtualization entirely by adding VirtualizingStackPanel.IsVirtualizing="False".

A better design might be to get that data from your underlying data model rather than relying on the UI events. Try handling the DataTable.ColumnChanged event on the DataTable.

Quartermeister
I'm not sure what you mean as far as handling the DataTable.ColumnChanged event, but the first soution worked perfectly! Thank you very much!
Randy