20

I'm using this snippet to analyze the rows I've selected on a datagrid.

for (int i = 0; i < dgDetalle.Items.Count; i++)
{
    DataGridRow row = (DataGridRow)dgDetalle.ItemContainerGenerator.ContainerFromIndex(i);
    FrameworkElement cellContent = dgDetalle.Columns[0].GetCellContent(row);
    // ... code ...
}

The cycle runs smoothly, but when processing certain indexes, the second line throws a null exception. MSDN's documentation says that ItemContainerGenerator.ContainerFromIndex(i) will return null if 'if the item is not realized', but this doesn't help me to guess how could I get the desired value.

How can I scan all the rows? Is there any other way?

UPDATE

I'm using this snippet to read a CheckBox as explained here. So I can't use binding or ItemSource at all unless I change a lot of things. And I cannot. I'm doing code maintenance.

Community
  • 1
  • 1
JPCF
  • 2,232
  • 5
  • 28
  • 50
  • 1
    I think there's an answer for your question: [How to loop over the rows of a WPF toolkit Datagrid](http://stackoverflow.com/questions/1934529/how-to-loop-over-the-rows-of-a-wpf-toolkit-datagrid). – Anatolii Gabuza May 14 '12 at 21:39

5 Answers5

25

Try this,

DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
        if (row == null)
        {
                          grid.UpdateLayout();
            grid.ScrollIntoView(grid.Items[index]);
            row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
        }
itzmebibin
  • 9,199
  • 8
  • 48
  • 62
13

The DataGrid is virtualizing the items, the respective rows (i.e. containers) are only created when the row is in view.

You could either turn off virtualization (which makes the first time loading very slow if you have many items, also the memory usage will be higher) or you just iterate over the data and check the values of the data objects' properties which should be bound to the data-grid. Usually you should not need the UI elements at all...

H.B.
  • 166,899
  • 29
  • 327
  • 400
  • I ran into this exact issue and after looking at the code, we didn't need the UI elements. Iterated over the data instead and everything is working great! – JChristian Oct 05 '12 at 00:56
3

Use this subscription:

TheListBox.ItemContainerGenerator.StatusChanged += (sender, e) =>
{
  TheListBox.Dispatcher.Invoke(() =>
  {
     var TheOne = TheListBox.ItemContainerGenerator.ContainerFromIndex(0) as ListBoxItem;
       if (TheOne != null)
         // Use The One
  });
};
Izzy Rodriguez
  • 2,097
  • 3
  • 21
  • 32
Amir
  • 770
  • 8
  • 21
0

In addition to other answers: items aren't available in constructor of the control class (page / window / etc).

If you want to access them after created, use Loaded event:

public partial class MyUserControl : UserControl
{
    public MyUserControl(int[] values)
    {
        InitializeComponent();

        this.MyItemsControl.ItemsSource = values;

        Loaded += (s, e) =>
        {
            for (int i = 0; i < this.MyItemsControl.Items.Count; ++i)
            {
                // this.MyItemsControl.ItemContainerGenerator.ContainerFromIndex(i)
            }
        };
    }
}
Pavel
  • 5,374
  • 4
  • 30
  • 55
0

In my case grid.UpdateLayout(); didn't help an I needed a DoEvents() instead:

    DataGridRow row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);

    if (row == null)
    {

        WPFTools.DoEvents();

        grid.ScrollIntoView(grid.Items[index]);
        row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
    }


    /// <summary>
    /// WPF DoEvents
    /// Source: https://stackoverflow.com/a/11899439/1574221
    /// </summary>
    public static void DoEvents()
    {
        var frame = new DispatcherFrame();

        Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background,
            new DispatcherOperationCallback(
                delegate (object f)
                {
                    ((DispatcherFrame)f).Continue = false;
                    return null;
                }), frame);

        Dispatcher.PushFrame(frame);
    }
marsh-wiggle
  • 2,508
  • 3
  • 35
  • 52