2017-03-01 3 views
1

Ich habe mehrere Expander-Steuerelemente in einer wpf-Benutzersteuerung. Wenn ich die Expander erweitern möchte ich automatisch scrollen, so dass der gesamte Expander sichtbar ist, wenn möglich. Zumindest ist der Expander so weit oben wie möglich.Wie scrolle ich, so dass ein Steuerelement nach dem Expandieren sichtbar ist?

Wenn ich es jetzt auf der Unterseite mache, dehnt es sich unter der Fensterkante aus und ich kann die Kontrollen im Expander nicht sehen, ohne manuell zu ihnen zu scrollen.

Und ich möchte dies von XAML und nicht das Codebehind tun. Ist das möglich? Ich verwende ein MVVM-Muster.

Im vorausgesetzt, dass ich einen Trigger auf der Expander verwenden müssen, aber ich habe keine Ahnung, wie die BringToView Funktionalität

Highlevel Layout Preform:

<ScrollViewer> 
    <UserControl> 
    <Grid> 
     <Expander> 
     ... 
     </Expander> 
     <Expander> 
     ... 
     </Expander> 
     <Expander> 
     ... 
     </Expander> 
    </Grid> 
    </UserControl> 
</ScrollViewer> 

Antwort

3

Handle Expanded Ereignis und rufen BringIntoView() Methode:

private void Expander_Expanded(object sender, RoutedEventArgs e) 
{ 
    ((Expander)sender).BringIntoView(); 
} 

Bitte beachten Sie, dass Sie Stackpanel oder etwas anderes statt Grid verwenden sollten:

<ScrollViewer Name="sv"> 
    <UserControl> 
     <StackPanel> 
      <Expander> 
       <Border Height="1000" Background="Red"/> 
      </Expander> 
      <Expander> 
       <Border Height="1000" Background="Blue"/> 
      </Expander> 
      <Expander Expanded="Expander_Expanded"> 
       <Border Height="1000" Background="Green"/> 
      </Expander> 
     </StackPanel> 
    </UserControl> 
</ScrollViewer> 

bearbeiten

Sie können diese angefügten Eigenschaft verwenden möchten:

public static class ExpanderEx 
{ 
    public static readonly DependencyProperty BringIntoViewOnExpandProperty = 
          DependencyProperty.RegisterAttached("BringIntoViewOnExpand", 
           typeof(bool), typeof(ExpanderEx), 
           new PropertyMetadata(false, OnBringIntoViewOnExpandChanged)); 


    public static bool GetBringIntoViewOnExpand(DependencyObject obj) 
    { 
     return (bool)obj.GetValue(BringIntoViewOnExpandProperty); 
    } 
    public static void SetBringIntoViewOnExpand(DependencyObject obj, bool value) 
    { 
     obj.SetValue(BringIntoViewOnExpandProperty, value); 
    } 
    private static void OnBringIntoViewOnExpandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     if (d is Expander) 
     { 
      Expander obj = (Expander)d; 
      if (e.NewValue.Equals(true)) 
       obj.Expanded += Obj_Expanded; 
      else 
       obj.Expanded -= Obj_Expanded; 
     } 
    } 

    private static void Obj_Expanded(object sender, RoutedEventArgs e) 
    { 
     ((Expander)sender).BringIntoView(); 
    } 
} 

und in XAML:

<ScrollViewer Name="sv"> 
    <UserControl> 
     <StackPanel> 
      <Expander local:ExpanderEx.BringIntoViewOnExpand="True"> 
       <Border Height="1000" Background="Red"/> 
      </Expander> 
      <Expander local:ExpanderEx.BringIntoViewOnExpand="True"> 
       <Border Height="1000" Background="Blue"/> 
      </Expander> 
      <Expander local:ExpanderEx.BringIntoViewOnExpand="True"> 
       <Border Height="1000" Background="Green"/> 
      </Expander> 
     </StackPanel> 
    </UserControl> 
</ScrollViewer> 
+0

Ich versuchte dies und es funktionierte. Aber nicht so, dass ich es geschafft habe :) Ich bin neu bei WPF, also ertragen Sie mit mir. Wo finde ich die ExpanderEx-Klasse, damit ich sie in vielen Ansichten wiederverwenden kann? Als ich es versuchte, musste ich die Klasse in das gleiche Projekt wie die Ansicht UND in die Ansicht codebehind setzen ... das kann nicht richtig sein ... – merger

+0

wählen Sie nach Ihrer Vorliebe. Es ist eine separate statische Klasse. B. Erstellen Sie eine Datei ** extensions.cs ** und legen Sie dort Ihre Erweiterungen ab. Wichtig ist, dass Sie [XAML-Namespace-Deklarationen] (https://msdn.microsoft.com/en-us/library/ms747086 (v = vs.110) .aspx) richtig festlegen. – Ron

+0

Ich hatte es in einer statischen Klasse. Ich glaube, ich habe etwas falsch gemacht, als ich es vorher getestet habe. Jetzt habe ich die Klasse in ein gemeinsames Projekt verschoben und VS den Namespace-Verweis in der XAML-Datei erstellen lassen, neu kompiliert und es hat funktioniert! Danke, dein Kommentar hat mich dazu gebracht, dasselbe auf eine andere Art zu versuchen und das hat es funktioniert :) – merger

2

jedem Expander die Prozedur für seine Expanded Ereignis Geben . Es sieht so aus, als ob Sie die Expander innerhalb einer UserControl definieren, also ist es schwierig, zu ScrollViewer zu gelangen. Eine Möglichkeit besteht darin, Ihrer UserControl eine ScrollViewer Abhängigkeitseigenschaft zu geben, die der Besitzer an alles bindet, was ScrollViewer enthält. Das mag ich nicht. Stattdessen habe ich eine Hilfsfunktion geschrieben, die den visuellen Baum nachschlägt und das nächste übergeordnete Element findet, falls vorhanden.

private void Expander_Expanded(object sender, RoutedEventArgs e) 
{ 
    var scrollViewer = GetNearestScrollViewerParent(); 

    if (scrollViewer == null) 
     return; 

    var expander = (Expander)sender; 

    UIElement container = VisualTreeHelper.GetParent(expander) as UIElement; 
    Point relativeLocation = expander.TranslatePoint(new Point(0, 0), container); 

    scrollViewer.ScrollToVerticalOffset(relativeLocation.Y); 
} 

public ScrollViewer GetNearestScrollViewerParent() 
{ 
    for (var parent = VisualTreeHelper.GetParent(this); 
     parent != null; 
     parent = VisualTreeHelper.GetParent(parent)) 
    { 
     if (parent is ScrollViewer) 
      return parent as ScrollViewer; 
    } 

    return null; 
} 

XAML:

<UserControl.Resources> 
    <Style TargetType="Expander" BasedOn="{StaticResource {x:Type Expander}}"> 
     <EventSetter Event="Expanded" Handler="Expander_Expanded" /> 
    </Style> 
</UserControl.Resources> 
Verwandte Themen