I have a TabControl
, in each TabItem
there is a DataGrid
. Each DataGridRow
has a button on the DataGridRowHeader
, which expands and collapses the RowDetails
.
As I use the row details expansion functionality, so have set the VirtualizingPanel ScrollUnit to Pixel, so scrolling is a bit more natural.
The program captures which rows have been expanded in an ObservableCollection<int>
which holds the row index to expand.
When I toggle to a new TabItem
and back to the original TabItem
, it loses which rows have been expanded.
Upon the DataContext
being changed, I'd like to use the ObservableCollection
to reset the expanded rows. I have tried this in the DataGrid
DataContextChanged
event.
public class DataGridBehaviors : Behavior<DataGrid>{
protected override void OnAttached(){
base.OnAttached();
this.AssociatedObject.DataContextChanged += DataGrid_DataContextChanged;
}
protected override void OnDetaching(){
this.AssociatedObject.DataContextChanged -= DataGrid_DataContextChanged;
base.OnDetaching();
}
private void DataGrid_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e){
ModuleGeometry oldModuleGeometry = (ModuleGeometry)e.OldValue;
ModuleGeometry newModuleGeometry = (ModuleGeometry)e.NewValue;
Task.Factory.StartNew(() => {
PerformRowExpansions(newModuleGeometry);
});
ScrollViewer scrollViewer = GetVisualChild<ScrollViewer>(this.AssociatedObject);
if (scrollViewer != null){
/*
* do some stuff
*/
}
}
private void PerformRowExpansions(ModuleGeometry newModuleGeometry){
ObservableCollection<int> tempExpandedIndexes = new ObservableCollection<int>(newModuleGeometry.ExpandedIndexes);
newModuleGeometry.ExpandedIndexes = new ObservableCollection<int>();
if (this.Dispatcher.CheckAccess()){
foreach (int index in tempExpandedIndexes)
{
DataGridRow row = this.AssociatedObject.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow;
row.DetailsVisibility = Visibility.Visible;
}
}
else{
this.Dispatcher.Invoke(new Action(() =>{
foreach (int index in tempExpandedIndexes){
DataGridRow row = this.AssociatedObject.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow;
row.DetailsVisibility = Visibility.Visible;
}
}));
}
}
private static T GetVisualChild<T>(DependencyObject parent) where T : Visual{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++){
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
child = GetVisualChild<T>(v);
if (child != null)
break;
}
return child;
}
}
However, it doesn't like doing this on rows that are not currently in the VirtualizingPanel
.
How can I accomplish this?
Should I just do the expand the currently virtualized rows?
Should the DataGrid
ScrollViewer
be manipulated programmatically as well? How can I account for the rows not visible in the ScrollViewer
?
Is there another object, other the DataGridRow
that I should be setting the RowDetails
Visibility
to?