Saturday, August 9, 2014

WPF DataGrid Row and Cells Extension Methods

Below are extension methods in accessing WPF DataGrid Rows and Cells. These methods were based on existing C# methods and I converted them to VB.NET for VB programmers.

WPF DataGrid Extension Methods:
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
Option Explicit On
Option Infer On
 
Imports System.Runtime.CompilerServices
Imports System.Windows.Controls.Primitives
 
Module DataGridExtensions
 
    ''' <summary>
    ''' Get DataGridRow using index
    ''' </summary>
    <Extension()>
    Function GetRow(ByVal grid As DataGrid, ByVal index As Integer) As DataGridRow
 
        Dim row As DataGridRow = DirectCast(grid.ItemContainerGenerator.ContainerFromIndex(index), DataGridRow)
        If row Is Nothing Then
            grid.UpdateLayout()
            grid.ScrollIntoView(grid.Items(index))
            row = DirectCast(grid.ItemContainerGenerator.ContainerFromIndex(index), DataGridRow)
        End If
 
        Return row
    End Function
 
    ''' <summary>
    ''' Return Selected Item
    ''' </summary>
    <Extension()>
    Function GetSelectedRow(ByVal grid As DataGrid) As DataGridRow
        Return DirectCast(grid.ItemContainerGenerator.ContainerFromItem(grid.SelectedItem), DataGridRow)
    End Function
 
    ''' <summary>
    ''' pass datagridrow and column index
    ''' </summary>
    <Extension()>
    Public Function GetCell(grid As DataGrid, row As DataGridRow, column As Integer) As DataGridCell
        If row IsNot Nothing Then
            Dim presenter As DataGridCellsPresenter = GetVisualChild(Of DataGridCellsPresenter)(row)
 
            If presenter Is Nothing Then
                grid.ScrollIntoView(row, grid.Columns(column))
                presenter = GetVisualChild(Of DataGridCellsPresenter)(row)
            End If
 
            Dim cell As DataGridCell = DirectCast(presenter.ItemContainerGenerator.ContainerFromIndex(column), DataGridCell)
            Return cell
        End If
        Return Nothing
    End Function
 
    ''' <summary>
    ''' Pass row and column index
    ''' </summary>
    <Extension()>
    Public Function GetCell(grid As DataGrid, row As Integer, column As Integer) As DataGridCell
        Dim rowContainer As DataGridRow = grid.GetRow(row)
        Return grid.GetCell(rowContainer, column)
    End Function
 
    ''' <summary>
    ''' Return DataGrid Rows 
    ''' </summary>
    <Extension()>
    Public Function GetDataGridRows(grid As DataGrid) As List(Of DataGridRow)
        Dim rows As New List(Of DataGridRow)
        Dim itemsSource = TryCast(grid.ItemsSource, IEnumerable)
 
        If itemsSource Is Nothing Then
            Return Nothing
        End If
 
        For Each item In itemsSource
            Dim row = TryCast(grid.ItemContainerGenerator.ContainerFromItem(item), DataGridRow)
 
            If row Is Nothing Then
 
                'bring into view and get row
                grid.UpdateLayout()
                grid.ScrollIntoView(item)
                row = TryCast(grid.ItemContainerGenerator.ContainerFromItem(item), DataGridRow)
 
            End If
 
            If row IsNot Nothing Then
                rows.Add(row)
            End If
        Next
 
        Return rows
 
    End Function
 
    ''' <summary>
    ''' Set selection based on indexes
    ''' </summary>
    <Extension()>
    Public Sub SelectDataGridRowByIndexes(dataGrid As DataGrid, ByVal ParamArray rowIndexes As Integer())
        If Not dataGrid.SelectionUnit.Equals(DataGridSelectionUnit.FullRow) Then
            Throw New ArgumentException("Change selection unit of the DataGrid to FullRow.")
        End If
 
        If Not dataGrid.SelectionMode.Equals(DataGridSelectionMode.Extended) Then
            Throw New ArgumentException("Change selectionMode of the DataGrid to Extended.")
        End If
 
        If rowIndexes.Length.Equals(0) OrElse rowIndexes.Length > dataGrid.Items.Count Then
            Throw New ArgumentException("Invalid number of indexes.")
        End If
 
        dataGrid.SelectedItems.Clear()
        dataGrid.UpdateLayout()
 
        For Each rowIndex As Integer In rowIndexes
        
            If rowIndex < 0 OrElse rowIndex > (dataGrid.Items.Count - 1) Then
                Throw New ArgumentException(String.Format("{0} is an invalid row index.", rowIndex))
            End If
 
            Dim item As Object = dataGrid.Items(rowIndex)
 
            Try
                dataGrid.SelectedItems.Add(item)
            Catch ex As Exception
 
            End Try
 
            Dim row As DataGridRow = TryCast(dataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex), DataGridRow)
 
            If row Is Nothing Then
                dataGrid.ScrollIntoView(item)
                row = TryCast(dataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex), DataGridRow)
            End If
 
            If row IsNot Nothing Then
                Dim cell As DataGridCell = GetCell(dataGrid, row, 0)
                If cell IsNot Nothing Then
                    cell.Focus()
                End If
            End If
        Next
    End Sub
 
    ''' <summary>
    ''' Traverse Visual Tree 
    ''' </summary>
    <Extension()>
    Public Function GetVisualChild(Of T As Visual)(parent As Visual) As T
        Dim child As T = Nothing
        Dim numVisuals As Integer = VisualTreeHelper.GetChildrenCount(parent)
 
        For i As Integer = 0 To numVisuals - 1
            Dim v As Visual = DirectCast(VisualTreeHelper.GetChild(parent, i), Visual)
            child = TryCast(v, T)
            If child Is Nothing Then
                child = GetVisualChild(Of T)(v)
            End If
 
            If child IsNot Nothing Then
                Exit For
            End If
        Next
 
        Return child
    End Function
 
End Module

Sample Output(Selecting DataGrid rows using index): Source Code: Accessing-Rows-and-Cells-in-a-WPF-DataGrid

Regards,
.NET Gene/KGComputers

2 comments: