2017-09-10 4 views
0

J'ai Expander avec imbriqué DataGrid sur l'application WPF - il crée usercontrols. Je crée ce contrôle sur codebehind pour chaque élément de la liste de données (de la base de données). Enfin, j'ai la liste où chaque élément est Expired avec DataGrid imbriqué. Quand je développe l'article je vois DataDrid, mais quand je développerai beaucoup de composants je dois faire défiler le contenu. Lorsque le curseur est sur l'expandeur, le scroll de l'élément fonctionne mais lorsque je souris sur le DataGrid, le scroll ne fonctionne pas.WPF - DataGrid niché dans Expander pas de défilement contenu DataGrid

Exemple de code:

<ScrollViewer HorizontalAlignment="Left"> 
<DockPanel> 
     <Expander x:Name="Expander1" Expanded="Expander1_Expanded"> 
     <Expander.Content> 
      <DataGrid x:Name="DataGrid1" MouseLeftButtonUp="DataGrid1_MouseLeftButtonDown" ScrollViewer.HorizontalScrollBarVisibility="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden" >   
       <DataGrid.CellStyle> 
        <Style TargetType="DataGridCell"> 
         <Setter Property="BorderThickness" Value="0"/> 
        </Style> 
       </DataGrid.CellStyle> 
       <DataGrid.Columns> 
        <DataGridTextColumn Header="name1" Binding="{Binding Name}" IsReadOnly="True" /> 
        <DataGridTextColumn Header="name2" Binding="{Binding Value}" IsReadOnly="True"/> 
        <DataGridTextColumn Header="name3" Binding="{Binding UnitName}" IsReadOnly="True"/> 
       </DataGrid.Columns> 
      </DataGrid> 
     </Expander.Content> 
     <Expander.Style> 
      <Style TargetType="Expander"> 
       <Setter Property="IsExpanded" Value="False" /> 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding IsExpanded, RelativeSource={RelativeSource Self}}" Value="True"> 
        </DataTrigger> 
       </Style.Triggers> 
      </Style> 
     </Expander.Style> 
    </Expander> 

// and mor expander, added from codebehind 

</DockPanel> 
</ScrollViewer> 

Enfin grille:

enter image description here

Lorsque la souris est l'endroit où défilement anneau vert à droite fonctionne

Répondre

1

Cela se produit depuis le même DataGrid peut contenir un ScrollViewer, qui apparaîtra lorsque vous avez plus d'articles que ce qui correspond à un heig donné ht. Dans ce cas, vous devez autoriser le DataGrid à tenter de gérer l'événement de défilement en premier, et s'il ne sait pas quoi faire à ce sujet, par exemple lorsque vous essayez de faire défiler vers le bas alors qu'il est déjà en bas, passez le faire défiler l'événement vers son parent.

Maintenant, il semble que votre DataGrid s ne sont pas réellement scrollable ce qui signifie que les éléments suivants pourrait être un peu exagéré, mais une solution générale qui réalise ci-dessus est obtenue en introduisant la modification suivante au gestionnaire de roulette de la souris:

/// <summary> 
/// Helper for allowing scroll events to pass from a <see cref="DataGrid"/> to its parent. 
/// This ensures that a "scroll down" event occurring at an already scrolled-down 
/// <see cref="DataGrid"/> will be passed on to its parent, which might be able to handle 
/// it instead. 
/// </summary> 
public class DataGridScrollCorrector 
{ 
    public static bool GetFixScrolling(DependencyObject obj) => 
     (bool)obj.GetValue(FixScrollingProperty); 

    public static void SetFixScrolling(DependencyObject obj, bool value) => 
     obj.SetValue(FixScrollingProperty, value); 

    public static readonly DependencyProperty FixScrollingProperty = 
     DependencyProperty.RegisterAttached("FixScrolling", typeof(bool), typeof(DataGridScrollCorrector), new FrameworkPropertyMetadata(false, OnFixScrollingPropertyChanged)); 

    private static void OnFixScrollingPropertyChanged(object sender, DependencyPropertyChangedEventArgs e) 
    { 
     var grid = sender as DataGrid; 
     if (grid == null) 
      throw new ArgumentException("The dependency property can only be attached to a DataGrid", nameof(sender)); 
     if ((bool)e.NewValue) 
      grid.PreviewMouseWheel += HandlePreviewMouseWheel; 
     else 
      grid.PreviewMouseWheel -= HandlePreviewMouseWheel; 
    } 

    /// <summary> 
    /// Finds the first child of a given type in a given <see cref="DependencyObject"/>. 
    /// </summary> 
    /// <typeparam name="T">The type of the child to search for.</typeparam> 
    /// <param name="depObj">The object whose children we are interested in.</param> 
    /// <returns>The child object.</returns> 
    private static T FindVisualChild<T>(DependencyObject depObj) where T : DependencyObject 
    { 
     if (depObj == null) return null; 
     for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) 
     { 
      DependencyObject child = VisualTreeHelper.GetChild(depObj, i); 
      var visualChild = child as T; 
      if (visualChild != null) return visualChild; 

      var childItem = FindVisualChild<T>(child); 
      if (childItem != null) return childItem; 
     } 
     return null; 
    } 

    /// <summary> 
    /// Attempts to scroll the <see cref="ScrollViewer"/> in the <see cref="DataGrid"/>. 
    /// If no scrolling occurs, pass the event to a parent. 
    /// </summary> 
    private static void HandlePreviewMouseWheel(object sender, MouseWheelEventArgs e) 
    { 
     var grid = sender as DataGrid; 
     var viewer = FindVisualChild<ScrollViewer>(grid); 

     if (viewer != null) 
     { 
      // We listen on changes to the ScrollViewer's scroll offset; if that changes 
      // we can consider our event handled. In case the ScrollChanged event is never 
      // raised, we take this to mean that we are at the top/bottom of our scroll viewer, 
      // in which case we provide the event to our parent. 
      ScrollChangedEventHandler handler = (senderScroll, eScroll) => 
       e.Handled = true; 

      viewer.ScrollChanged += handler; 
      // Scroll +/- 3 rows depending on whether we are scrolling up or down. The 
      // forced layout update is necessary to ensure that the event is called 
      // immediately (as opposed to after some small delay). 
      double oldOffset = viewer.VerticalOffset; 
      double offsetDelta = e.Delta > 0 ? -3 : 3; 
      viewer.ScrollToVerticalOffset(oldOffset + offsetDelta); 
      viewer.UpdateLayout(); 
      viewer.ScrollChanged -= handler; 
     } 

     if (e.Handled) return; 
     e.Handled = true; 
     var eventArg = 
      new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta) 
      { 
       RoutedEvent = UIElement.MouseWheelEvent, 
       Source = sender 
      }; 
     var parent = ((Control)sender).Parent as UIElement; 
     parent?.RaiseEvent(eventArg); 
    } 
} 

Ici, le 3 codé en dur correspond au nombre de lignes à faire défiler dans DataGrid. Vous devez ensuite appliquer ce correcteur à tous les codes pertinents DataGrid s. Par exemple, pour l'utiliser sur toutes les grilles dans l'application, vous pouvez l'ajouter à votre Application.Resources en App.xaml comme suit:

<Application x:Class="WpfApplication1.App" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:local="clr-namespace:WpfApplication1" 
      StartupUri="MainWindow.xaml"> 
    <Application.Resources> 
     <Style TargetType="DataGrid"> 
      <Setter Property="local:DataGridScrollCorrector.FixScrolling" Value="True" /> 
     </Style> 
    </Application.Resources> 
</Application> 

Crédit: Cette solution est un peu basée sur/inspiré de celui mentionné in this blog post mais limite sa fonction à DataGrid (puisque dans mon expérience, il va casser un tas d'autres contrôles qui ne sont pas prêts à tunnelliser leurs événements).

+0

C'est génial. Le code que vous avez fourni et le lien de blog ont résolu mon problème – 18666