2010-02-22 32 views
8

想象一下您打开WPF Popup的情况(例如通过ButtonClick)。 你有一个ListBox直接在Popup与一些项目,所以你必须能够滚动。 想象一下,这是您的Custom Control,它位于ScrollViewerWPF检测滚动父级控制

现在,如果您将鼠标从Popup表面外移动并滚动,会发生什么情况? 你上下滚动,但打开Popup!这就是问题所在。

问题是,如何从Control内部检测到VisualTree中的其他未知父控件已经开始滚动? 并连续设置IsDropDownOpen = false

+0

我有同样的问题和问题。我滚动我的网格,我的弹出与自定义操作留在同一个地方!我需要滚动弹出与网格! – Evgeny

回答

10

我们可以编写一个触发器,用于包含在ScrollViewer中的元素。下面是一个完整的示例应用程序:

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

我们打开一个PopupScrollViewer导致ScrollTrigger行动射击,然后我们可以关闭弹出任何父任何滚动按钮。请注意,触发器连接到Button而不是Popup。我们可以使用视觉树中的任何附近元素。另请注意,我们使用另一个触发器来打开Popup,但它如何打开对原始问题并不重要。

这里是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; 
    } 
} 

ScrollTrigger很简单,它只是连接到所有父ScrollChanged事件,并触发任何包含动作。在示例中,我们使用ChangePropertyAction关闭Popup

如果你不熟悉的行为,安装的Expression Blend 4 SDK,并添加这些命名空间:

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

,并添加System.Windows.InteractivityMicrosoft.Expression.Interactions到您的项目。

1

我不太了解您的控件是如何实现的,但是您不能基于Focus事件的控件打开/关闭吗?如果它失去了重点,关闭弹出窗口? 也许我明白错了,你能发表一段代码吗? Daniel