2010-02-22 47 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