2008-11-16 16 views
6

Estoy intentando sincronizar la posición horizontal de desplazamiento de 2 WPF DataGrid controles.posiciones Sincronización de desplazamiento para 2 DataGrids WPF

Me inscribo a la ScrollChanged caso de la primera cuadrícula de datos:

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

tengo una segunda cuadrícula de datos:

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

En el controlador de eventos yo estaba tratando de utilizar el IScrollInfo.SetHorizontalOffset, pero lamentablemente, DataGrid no expone IScrollInfo:

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

¿Hay alguna otra manera de lograr esto? ¿O hay otro elemento en TargetGrid que expone el necesario IScrollInfo para lograr la sincronización de las posiciones de desplazamiento?

BTW, soy utilizando columnas congeladas, por lo que no puedo ajustar ambos controles DataGrid con ScrollViewers.

Respuesta

3

De acuerdo con el grupo de productos de Microsoft, el método recomendado es atravesar el árbol visual para encontrar el ScrollViewer, como explained in their answer on Codeplex.

+0

Sí. Aunque hice lo mismo de la misma manera en el pasado. Simplemente parece que no deberíamos tener que hackear el árbol visual de esta manera. Simplemente otra forma en que WPF es áspero en los bordes. – PeterAllenWebb

+2

Tenga cuidado cuando el usuario cambie los temas visuales: controle y luego obtenga nuevas plantillas (= nuevos árboles visuales), y mantendrá la referencia a un visualizador de desplazamiento incorrecto. Debería reaccionar en OnApplyTemplate y buscar el ScrollViewer real cada vez que se invoca. Consulte http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.onapplytemplate.aspx –

1

Tuvimos este mismo problema al usar la cuadrícula Infragistics porque no hizo (todavía no lo hace) admite columnas inmovilizadas. Así que teníamos dos cuadrículas una al lado de la otra que se hicieron para que parecieran una sola. La cuadrícula de la izquierda no se desplazó horizontalmente, pero sí la cuadrícula de la derecha. Columnas congeladas del pobre.

De todos modos, terminamos alcanzando el árbol visual y sacando el ScrollViewer nosotros mismos. Después de todo, sabíamos que estaba allí; simplemente no estaba expuesto por el modelo de objetos. Podría utilizar un enfoque similar si la cuadrícula WPF no expone el ScrollViewer. O podría crear una subclase de la grilla y agregar la funcionalidad que necesita para que esto funcione.

Interesado en saber por qué necesita hacer esto.

+0

Tengo la fuente del WPF Toolkit DataGrid de Codeplex, por lo que podría encontrarlo y exponerlo (no es mi método preferido). Soy stac king 2 grillas para obtener el efecto de panel congelado (ala Excel). –

0

Esta es una gran solución. Funcionó bien para mí en WPF.

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

acabo de hacer una referencia a ScrollSynchronizer DLL, añade una importación de xml:

xmlns: desplazarse = "CLR-espacio de nombres: ScrollSynchronizer"

continuación, se agregó esto a mis dos DataGrids y bobs a su tío:

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

puede engañar a la cuadrícula de datos para exponer su ScrollViewer como propiedad pública para cada cuadrícula, cuando por ejemplo, el controlador innerGridControl_ScrollChanged() llamado durante la inicialización del control de usuario. Para exponerlo, puede hacer su cuadrícula en un archivo de vista xaml, y luego componer dos de ellos en otra vista xaml. A continuación código está en la innerGrid.xaml.cs por ejemplo:

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; 
     } 
    } 

en OuterGridView.xaml poner definición controlador de eventos adjunto:

<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> 

continuación, acceder a esa ScrollViewer.SetHorizontalOffset pública (e.HorizontalOffset) método cuando ocurre otro evento de desplazamiento. A continuación el código de la OuterGridView.xaml.cs en una de la definición manejador (

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; 
     } 
    } 

También asegúrese de que cualquier otro evento scroll_changed dentro de la rejilla interna (si los hay, por ejemplo, si se define un cuadro de texto con la rueda de desplazamiento predeterminado en una de las plantillas de datos de la columna) tiene su e.Handled configurado en true para evitar que el manejador de la cuadrícula externa lo procese (esto sucedió debido al comportamiento de burbujeo predeterminado de routedevents). Alternativamente puede poner adicional if check en e.OriginalSource o e.Source para filtrar el evento de desplazamiento que debe procesar.

Cuestiones relacionadas