1
votes

I have a scenario where I want to show hierarchical data in a DataGrid in Silverlight 3 while having the header rows still have the standard set of cells and being editable. The user needs to be able to collapse and expand rows to hide child rows.

I've accomplished this by having a button on each parent row that looks like either a collapse or an expand glyph depending on its state. Clicking this manipulates a property on the data item for its child rows. Each row has its visibility bound to this property of the data item.

This works somewhat decently, though it does have performance problems with the grid rendering more columns than it needs to.

My problem now is that when the user hits up or down on the keyboard they are able to navigate to hidden rows.

For example if I have a structure like

1 Parent (Expanded, Visible)

1a (Visible)

1b (Visible)

2 Parent (Collapsed, Visible)

2a (Hidden)

3 Parent (Expanded, Visible)

3a (Visible)

If I have [2 Parent] selected and I hit the down arrow on the keyboard I would expect the selection to go to [3 Parent] but it goes to [2a] instead even though [2a]'s row visibility is set to Visibility.Collapsed.

I'd like to be able to either intercept the keyboard event (via something like the non-existent PreviewKeyDown event) and handle it myself or to find some way of tricking the DataGrid's internals of moving to the correct item.

At this point I am fairly invested in tweaking the row visibility for hiding these items.

Any ideas?

1

1 Answers

1
votes

Okay, I was thinking about this after I posted it. I had tried using PagedCollectionView for grouping and wasn't happy with the group styles but I hadn't tried using it for filtering.

I'm now wrapping my DataGrid's old ItemsSource inside of a PagedCollectionView and then setting the Filter of it to a method that returns based on the visibility property of my data item.

  Private Sub UpdateFilter(ByVal view As PagedCollectionView)
    If view IsNot Nothing Then
      view.Filter = Nothing
      view.Filter = New Predicate(Of Object)(AddressOf FilterRows)
    End If
  End Sub

  Private Function FilterRows(ByVal obj As Object) As Boolean
    Dim item As MyDataItem = obj
    Return item.IsVisible = Windows.Visibility.Visible
  End Function

The only problem with this approach is that since it's not using binding to filter it will not refresh the filter if it sees a property changed event on MyDataItem.IsVisible

To solve this, I'm responding to events on my row items and calling UpdateFilter every time an item is expanded or collapsed. I'm nulling out View.Filter because if I don't then the DataGrid won't update its set of filtered rows.

This also solves my performance woes involving collapsing / expanding since the DataGrid handles filtered rows much better since it doesn't have to instantiate a row just to have its visibility set to Collapsed.

Hope this helps anyone else out there with similar difficulties.