mardi 25 juillet 2017

WPF datagrid and Item Container Recycling

In WPF I have a dialog window with an embedded datagrid. The purpose of the dialog is to select files to upload. I've added a column in the datagrid to allow selection. But there is a fairly complicated relationship between the rows -- uploading one file may require the upload a parent file, for example. Because of that, there is a handler that updates the checkboxes (checking/unchecking and setting isEnabled off/on)

I seem to have run into a problem with "Item Container Recycling" when I get many rows in the datagrid. Some of the definition looks like

       <DataGrid Name="myGrid" 
                      ...
                      VirtualizingPanel.IsVirtualizing="True"
                      VirtualizingPanel.VirtualizationMode="Standard">
            <DataGrid.Resources>
                <Style TargetType="DataGridColumnHeader"  x:Key="DataGridHeaderStyle" >
                </Style>
                <Style x:Key="SingleClickEditing"  TargetType="{x:Type DataGridCell}">
                    <EventSetter Event="PreviewMouseLeftButtonDown" Handler="DataGridCell_PreviewMouseLeftButtonDown"></EventSetter>
                    <EventSetter Event="CheckBox.Checked" Handler="OnChecked"/>
                    <EventSetter Event="CheckBox.Unchecked" Handler="OnChecked"/>
                </Style>
                ...

When I first created the datagrid I was not able to access all rows of the datagrid until I set:

 VirtualizingPanel.VirtualizationMode="Standard"

Now on dialog initialization I find that I can access all rows of the grid and set them up OK.

But the odd thing is that later when the user clicks on a checkbox, the checkbox handler method attempts to access the checkbox from other rows to set them. But then again not all of the rows are available and I see strange results.

It is as if the following got turned off for the datagrid. VirtualizingPanel.VirtualizationMode="Standard"

Programmatically in the cs code for the dialog I don't see that I am able to access a parameter grid.VirtualizingPanel to see what the value is.

I try to get all the rows of the grid as follows:

    private List<DataGridRow> GetDataGridRows(DataGrid grid)
    {
        var itemsSource = grid.ItemsSource as IEnumerable;
        List<DataGridRow> rows = new List<DataGridRow>();
        if (null == itemsSource) return null;
        foreach (var item in itemsSource)
        {
            DataGridRow row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
            if (row!=null) rows.Add(row);
        }
        return rows;
    }

The problem is that sometimes the following returns null:

grid.ItemContainerGenerator.ContainerFromItem(item)

How I can I make sure that I can always get a list of all rows?




Aucun commentaire:

Enregistrer un commentaire