2010-02-22 17 views
8

Imagine la situación en la que abre un WPF Popup (por ejemplo, a través de ButtonClick). Tiene un ListBox directamente en el Popup con algunos elementos, por lo que debe poder desplazarse. Imagine que este es su Custom Control y se encuentra en el ScrollViewer.WPF detectar control primario desplazable

Ahora, si se mueve con el mouse hacia afuera desde la superficie Popup y se desplaza, ¿qué ocurre? Se desplaza hacia arriba y hacia abajo, pero con el Popup abierto. Y ese es el problema.

La pregunta es, ¿cómo detectar desde dentro del Control, que algún otro Control parental desconocido en el VisualTree ha comenzado a desplazarse? y configurado consecutivamente IsDropDownOpen = false?

+0

Tengo la misma pregunta y problema. ¡Desplazo mi cuadrícula y mi ventana emergente con operaciones personalizadas permanece en el mismo lugar! Necesito desplazar ventana emergente con grilla! – Evgeny

Respuesta

10

Podemos escribir un disparador para usarlo con elementos contenidos en un ScrollViewer. Aquí es una aplicación de ejemplo completo:

<Grid> 
    <ScrollViewer VerticalAlignment="Top" Height="200"> 
     <StackPanel HorizontalAlignment="Left"> 
      <Button Name="button" Content="Open"> 
       <i:Interaction.Triggers> 
        <i:EventTrigger EventName="Click"> 
         <ei:ChangePropertyAction TargetObject="{Binding ElementName=popup}" PropertyName="IsOpen" Value="True"/> 
        </i:EventTrigger> 
        <local:ScrollTrigger> 
         <ei:ChangePropertyAction TargetObject="{Binding ElementName=popup}" PropertyName="IsOpen" Value="False"/> 
        </local:ScrollTrigger> 
       </i:Interaction.Triggers> 
      </Button> 
      <Popup Name="popup" PlacementTarget="{Binding ElementName=button}"> 
       <TextBlock Background="White" Text="Sample text"/> 
      </Popup> 
      <Rectangle Width="100" Height="100" Fill="Red"/> 
      <Rectangle Width="100" Height="100" Fill="Green"/> 
      <Rectangle Width="100" Height="100" Fill="Blue"/> 
      <Rectangle Width="100" Height="100" Fill="Yellow"/> 
     </StackPanel> 
    </ScrollViewer> 
</Grid> 

Tenemos un botón que abre un Popup y cualquier desplazamiento en cualquier padre ScrollViewer hace que las acciones ScrollTrigger al fuego y entonces podemos cerrar la ventana emergente. Tenga en cuenta que el activador está conectado al Button y no al Popup. Podemos usar cualquier elemento cercano que esté en el árbol visual. También tenga en cuenta que usamos otro disparador para abrir el Popup, pero cómo se abre no es importante para la pregunta original.

Aquí es el ScrollTrigger:

class ScrollTrigger : TriggerBase<FrameworkElement> 
{ 
    protected override void OnAttached() 
    { 
     AssociatedObject.Loaded += new RoutedEventHandler(AssociatedObject_Loaded); 
    } 

    void AssociatedObject_Loaded(object sender, RoutedEventArgs e) 
    { 
     foreach (var scrollViewer in GetScrollViewers()) 
      scrollViewer.ScrollChanged += new ScrollChangedEventHandler(scrollViewer_ScrollChanged); 
    } 

    void scrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) 
    { 
     InvokeActions(e.OriginalSource); 
    } 

    IEnumerable<ScrollViewer> GetScrollViewers() 
    { 
     for (DependencyObject element = AssociatedObject; element != null; element = VisualTreeHelper.GetParent(element)) 
      if (element is ScrollViewer) yield return element as ScrollViewer; 
    } 
} 

El ScrollTrigger es muy simple, sólo se concede a todos los eventos de los padres ScrollChanged y dispara cualquier acción que contenían. En la muestra usamos el ChangePropertyAction para cerrar el Popup.

Si no está familiarizado con los comportamientos, instale el Expression Blend 4 SDK y agregar estos espacios de nombres:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 

y añadir System.Windows.Interactivity y Microsoft.Expression.Interactions a su proyecto.

1

No me imagino cómo son sus controles, pero ¿no puede basar su apertura/cierre de un control en el evento Focus? Y si pierde el foco, para cerrar la ventana emergente? Quizás entiendo mal, ¿puedes publicar un fragmento de código? Daniel