Sync scroll positions for 2 rows of WPF data

I am trying to synchronize the horizontal scroll position of 2 WPF DataGrid controls .

I subscribe to the ScrollChanged event of the first DataGrid:

<toolkit:DataGrid x:Name="SourceGrid" ScrollViewer.ScrollChanged="SourceGrid_ScrollChanged"> 

I have a second DataGrid:

 <toolkit:DataGrid x:Name="TargetGrid"> 

In the event handler, I tried to use IScrollInfo.SetHorizontalOffset , but, alas, the DataGrid does not open IScrollInfo :

 private void SourceGrid_ScrollChanged(object sender, ScrollChangedEventArgs e) { ((IScrollInfo)TargetGrid).SetHorizontalOffset(e.HorizontalOffset); // cast to IScrollInfo fails } 

Is there any other way to do this? Or is there another TargetGrid element that provides the necessary IScrollInfo to achieve scroll position synchronization?

BTW, I'm using frozen columns , so I can't wrap both DataGrid controls with ScrollViewers.

+6
scroll wpf datagrid
source share
5 answers

According to Microsoft's product group, traversing the visual tree to search for ScrollViewer is the recommended method, as explained in their answer to Codeplex .

+3
source share
+2
source share

We had the same problem when using the Infragistics grid, because it did not support frozen columns (does not support). So we had two meshes that were made to look like one. The grid on the left did not scroll horizontally, but the grid on the right. Poor people are frozen columns.

In any case, we ended up just reaching the visual tree and pulling out the ScrollViewer ourselves. In the end, we knew that he was there - he simply was not exposed as an object model. You can use a similar approach if the WPF grid does not provide a ScrollViewer. Or you can subclass the grid and add the necessary functions to do the job.

Interested in finding out why you need to do this.

+1
source share

You can trick the datagrid to open your ScrollViewer as a public property for each grid when, for example, it called the innerGridControl_ScrollChanged () handler during usercontrol initialization. To open it, you can make your grid in a xaml View file, and then compose two of them in a different xaml view. Below code is on innerGrid.xaml.cs, for example:

  public ScrollViewer Scroller { get; set; } // exposed ScrollViewer from the grid private bool _isFirstTimeLoaded = true; private void innerGridControl_ScrollChanged(object sender, ScrollChangedEventArgs e) { if (_isFirstTimeLoaded) // just to save the code from casting and assignment after 1st time loaded { var scroller = (e.OriginalSource) as ScrollViewer; Scroller = scroller; _isFirstTimeLoaded = false; } } 

in OuterGridView.xaml puts the definition of the attached event handler:

 <Views:innerGridView Grid.Row="1" Margin="2,0,2,2" DataContext="{Binding someCollection}" x:Name="grid1Control" ScrollViewer.ScrollChanged="Grid1Attached_ScrollChanged" ></Views:innerGridView> <Views:innerGridView Grid.Row="3" Margin="2,0,2,2" DataContext="{Binding someCollection}" x:Name="grid2Control" ScrollViewer.ScrollChanged="Grid2Attached_ScrollChanged" ></Views:innerGridView> 

then go into this public ScrollViewer.SetHorizontalOffset (e.HorizontalOffset) method when another scroll event occurs. Below code is in OuterGridView.xaml.cs in one of the handler definitions (

 private void Grid1Attached_ScrollChanged(object sender, ScrollChangedEventArgs e) { if (e != null && !e.Handled) { if (e.HorizontalChange != 0.0) { grid2Control.Scroller.ScrollToHorizontalOffset(e.HorizontalOffset); } e.Handled = true; } } private void Grid2Attached_ScrollChanged(object sender, ScrollChangedEventArgs e) { if (e != null && !e.Handled) { if (e.HorizontalChange != 0.0) { grid1Control.Scroller.ScrollToHorizontalOffset(e.HorizontalOffset); } e.Handled = true; } } 

Also make sure that any other scroll_changed event is inside the internal grid (if there is, for example, if you define a TextBox with a default scroller in one of the column data templates), its e.Handled is set to true to prevent it from processing the external grid handler (this was due to the default bubbling behavior of routedevents). Alternatively, you can add additional data if checking for e.OriginalSource or e.Source to filter the scroll event that you are going to handle.

+1
source share

This is a great solution. Worked great for me in WPF.

http://www.codeproject.com/Articles/39244/Scroll-Synchronization

I just made a link to the ScrollSynchronizer DLL, added the xml import:

xmlns: scroll = "clr-namespace: ScrollSynchronizer"

then just added this to both my datagrids and your uncles:

 <DataGrid.Resources> <Style TargetType="ScrollViewer"> <Setter Property="scroll:ScrollSynchronizer.ScrollGroup" Value="Group1" /> </Style> </DataGrid.Resources> 
0
source share

All Articles