I've searched online and have tried myself and am unable to find a way to accurately select a record programming by providing a search value on a datagrid that has grouped data. The code below that I have works on ungrouped data, but when the data is grouped, the index seems to no longer be valid and the grouping seems to have it's on index on the data.
Here is a screen shot of the form. The data is grouped. The user types in a sales order number and clicks the find button. I'd like to record that is found for that row to be highlighted.
This is the data ungrouped when a record is found, you can see the record is highlighted:
Below is my code. The OnSelectionButtonClick event is fired when the Find button is clicked. Data is grouped/ungrouped in the cmdAddRemoveGroup_Click procedure. Data is bound to the grid in the RebindData procedure. A sales order is passed into the SelectGridRow procedure to select a row if found.
Any help is appreciated! Thanks, Jimmy
'Module level scope
Private da As wpfProductionDashboard.flexDataSetTableAdapters.vwProductionScheduleWPFMainTableAdapter = New wpfProductionDashboard.flexDataSetTableAdapters.vwProductionScheduleWPFMainTableAdapter()
Private Sub OnSelectionButtonClick(sender As Object, e As RoutedEventArgs)
Try
Dim so As Integer = Convert.ToInt32(Me.txtFind.Text)
Dim index As Integer = FlexDataSet.vwProductionScheduleWPFMain.Rows.IndexOf(FlexDataSet.vwProductionScheduleWPFMain.Rows.Find(so))
'Dim index2 As Integer = 1
'For Each c In FlexDataSet.vwProductionScheduleWPFMain.Rows
' If c(0) = so Then
' SelectGridRow(dataGrid1, index2)
' Exit Sub
' End If
' Console.WriteLine(c(0))
' index2 += 1
'Next
If index > 0 Then
Console.WriteLine(index.ToString())
SelectGridRow(dataGrid1, index)
End If
Catch ex As Exception
MessageBox.Show(ex.Message, "Find button click error", MessageBoxButton.OK, MessageBoxImage.Error)
End Try
End Sub
Private Sub SelectGridRow(ByVal DataGrid As DataGrid, ByVal rowIndex As Integer)
If Not DataGrid.SelectionUnit.Equals(DataGridSelectionUnit.FullRow) Then
Throw New ArgumentException("The SelectionUnit of the DataGrid must be set to FullRow.")
End If
If rowIndex < 0 OrElse rowIndex > (DataGrid.Items.Count - 1) Then
Throw New ArgumentException(String.Format("{0} is an invalid row index.", rowIndex))
End If
DataGrid.SelectedItems.Clear()
Dim item As Object = DataGrid.Items(rowIndex)
DataGrid.SelectedItem = item
Dim row As DataGridRow = TryCast(DataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex), DataGridRow)
If row Is Nothing Then
' bring the data item into view
DataGrid.ScrollIntoView(item)
row = TryCast(DataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex), DataGridRow)
End If
End Sub
Private Sub cmdAddRemoveGroup_Click(sender As Object, e As RoutedEventArgs) Handles cmdAddRemoveGroup.Click
Try
If cmdAddRemoveGroup.IsChecked = False Then
FlexDataSet.vwProductionScheduleWPFMain.DefaultView.RowFilter = "SalesOrderStatus <> 'Hold' and SalesOrderStatus <> 'Approval Done'"
vw.GroupDescriptions.Add(New PropertyGroupDescription("SalesOrderStatusGroup", New OpenStatusConverter))
Else
vw.GroupDescriptions.Clear()
End If
SortDataGrid()
Catch ex As Exception
MessageBox.Show(ex.Message, "Grouping Event", MessageBoxButton.OK, MessageBoxImage.Error)
End Try
End Sub
Private Sub RebindData()
Try
Dim taStatuses As wpfProductionDashboard.flexDataSetTableAdapters.spGetProductionDashboardStatusesTableAdapter = New wpfProductionDashboard.flexDataSetTableAdapters.spGetProductionDashboardStatusesTableAdapter()
da.Fill(FlexDataSet.vwProductionScheduleWPFMain)
taStatuses.Fill(FlexDataSet.spGetProductionDashboardStatuses)
vw.View.MoveCurrentToFirst()
cvOrderStatuses.View.MoveCurrentToFirst()
lstOrderStatus.ItemsSource = cvOrderStatuses.View
Catch ex As Exception
MessageBox.Show(ex.Message, "Rebind Data Event", MessageBoxButton.OK, MessageBoxImage.Error)
End Try
End Sub
Thanks Konstantin. I was afraid you were going to say that. I haven't figured out how to implement an ObservableCollection as this app doesn't use MVVM. If you don't mind, and I understand if you do and don't want to, would you mind try to help me see if I can bind to an ObservableCollection via my current implementation? Below is my xaml and explanation.
<Window.Resources>
<local:flex2kSQLDataSet x:Key="Flex2kSQLDataSet" />
<CollectionViewSource x:Key="cvOrderStatuses" Source="{Binding spGetProductionDashboardStatuses, Source={StaticResource Flex2kSQLDataSet}}" />
<CollectionViewSource x:Key="VwProductionScheduleWPFMainViewSource" Source="{Binding vwProductionScheduleWPFMain, Source={StaticResource Flex2kSQLDataSet}}" />
<Grid DataContext="{StaticResource VwProductionScheduleWPFMainViewSource}">
VwProductionScheduleWPFMainViewSource uses a SQL Server view and a table adapter. Is it possible to use this view and create an ObservableCollection and bind it to the datagrid? If so, if you could help with code suggestion or point me in the right direction, I'd greatly appreciate it!
UPDATE #3: Konstantin, I think I'm close but need a little more help.
Module level: Private Item As Object
Private Property Items() As ObservableCollection(Of vwProductionScheduleWPFMain)
Get
Return m_Items
End Get
Set(value As ObservableCollection(Of vwProductionScheduleWPFMain))
m_Items = value
End Set
End Property
Private m_Items As ObservableCollection(Of vwProductionScheduleWPFMain)
Form load: Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs) Handles MyBase.Loaded Try
dataGrid1.DataContext = Me
Bind data procedure: Private Sub BindData() Try Dim db As TFCDataContext
db = New TFCDataContext
Items = New ObservableCollection(Of vwProductionScheduleWPFMain)(db.vwProductionScheduleWPFMains)
dataGrid1.ItemsSource = Items
Find procedure: Private Sub OnSelectionButtonClick(sender As Object, e As RoutedEventArgs) Try Dim so As Integer = Convert.ToInt32(Me.txtFind.Text)
Item = Items.Where(Function(x) x.SalesOrder = so)
dataGrid1.SelectedItem = Item
Catch ex As Exception
MessageBox.Show(ex.Message, "Find button click error", MessageBoxButton.OK, MessageBoxImage.Error)
End Try
End Sub
XAML for grid:
I'm able to see that my Items observable collection is getting the correct data and that the find method successfully find the record. However, the found record does not select the record in the grid. What am I missing to make it find the record in the grid?
Also, I noticed that if I remove setting the DataContext on the load event, the data is still loaded. Is setting the DataContext to (me/this) needed or am I doing it incorrectly? Thanks again for your help!
UPDATE #4: I've successfully found the item searched for in the observable Items collection and assigned it to an object Item, but when I set the SelectedItem property of the datagrid, the row is not selected, which is what I really need. If you could help or provide sample code, it would be much appreciated. Below is my code showing the item has been found (but the row isn't selected).
XAML for datagrid with ItemSource and SelectedItem set:
<DataGrid x:Name="dataGrid1"
AutoGenerateColumns="False"
CanUserReorderColumns="True"
CanUserAddRows="False"
IsReadOnly="False"
CanUserResizeColumns="True"
EnableRowVirtualization="True"
ItemsSource="{Binding Items}"
SelectedItem="{Binding Item}"
CanUserSortColumns="True"
RowHeight="25"
Margin="10,15,10,10"
Grid.Row="3"
Sorting="DataGrid_Standard_Sorting">
An ObservableCollection is the best implementation. Example code below.
Public Property MyCollection() As ObservableCollection(Of YourClass)
Get
Return m_MyCollection
End Get
Set(value As ObservableCollection(Of YourClass))
m_MyCollection = value
End Set
End Property
Private m_MyCollection As New ObservableCollection(Of YourClass)
Dim findItem As YourClass
findItem = MyCollection.First(Function(x) x.SalesOrder = so)
dataGrid1.SelectedItem = findItem
dataGrid1.ScrollIntoView(findItem)