TonyW TonyW - 4 days ago 6
Vb.net Question

DataGrid SelectedItems for each loop exception

As I'm scrolling through the datagrid and selecting items on and off the visible screen, it throws the following exception.

Object reference not set to an instance of an object.


Dim sn as string
is the culprit...

For Each item In asset_MasterDataGrid.SelectedItems
If item IsNot Nothing Then
Dim snIndex As Integer = asset_MasterDataGrid.Columns.IndexOf(asset_MasterDataGrid.Columns.LastOrDefault(Function(c) c.Header = "serial num"))
Dim sn As String = DirectCast(asset_MasterDataGrid.SelectedCells(snIndex).Column.GetCellContent(item), TextBlock).Text
variables.selectedAssets.Add(sn)
End If
Next


When
EnableRowVirtualization="True"
is true, I get the error. I'm assuming this is because once I scroll off the screen, while having rows selected, those rows no longer exist.

How do I avoid this, without turning off virtualization?

Answer

Here's the final version, with OP's corrections of my strange attempts at VB syntax:

Dim snIndex As Integer = asset_MasterDataGrid.Columns.IndexOf(asset_MasterDataGrid.Columns.LastOrDefault(Function(c) c.Header = "serial num"))

'loop through all selected datagrid rows.
For Each item In asset_MasterDataGrid.SelectedItems
    'check to see if item has a NULL value, it shouldn't be though.
    If item IsNot Nothing Then
        'directcast item (selected item) to a datarowview.
        Dim drv As DataRowView = DirectCast(item, DataRowView)
        'declare serial number to a string.
        Dim sn As String = drv.Row(snIndex)
        'add all serial numbers to selected asset list (so we can get a list of all the selected sn's).
        variables.selectedAssets.Add(sn)
    End If
Next

I think you were getting the null reference exception because you were trying to cast some part of selected item to a TextBlock, but there's nothing in there that's castable to that.

In WPF, SelectedItems means the data items that are being displayed in the UI, not the actual UI stuff. It's a subset of the whole collection items that you gave to ItemsSource -- whatever those are, that's what it's "selecting" when the user clicks on the grid. I had to populate my DataGrid like so:

myDataGrid.ItemsSource = myDataTable.DefaultView;

DefaultView returns a DataView which implements IEnumerable. Enumerate it, and it gives you DataRowView instances. And those are what the DataGrid gives you back in SelectedItems.

But I know just about zero about DataTable. If you did it some other way, if there is some other way, you may get something else back. So put a breakpoint in that loop and examine item; see what type it is. It's going to be something that represents one of your data rows, or I'll eat my hat(1).

(1) That's an exclusive OR.

Comments