2010-02-22 7 views
8

Hãy tưởng tượng tình huống bạn mở một WPF Popup (ví dụ: thông qua ButtonClick). Bạn có một số ListBox trực tiếp trong Popup với một số mục, vì vậy bạn phải có khả năng cuộn. Hãy tưởng tượng rằng đây là số Custom Control của bạn và nằm ở số ScrollViewer.WPF phát hiện cha mẹ cuộn Kiểm soát

Bây giờ nếu bạn di chuyển bằng chuột bên ngoài từ bề mặt và cuộn Popup, thì điều gì sẽ xảy ra? Bạn cuộn lên và xuống nhưng đã mở Popup! Và đó là vấn đề.

Câu hỏi đặt ra là, làm cách nào để phát hiện từ bên trong Kiểm soát, một số Kiểm soát cha mẹ không xác định khác trong VisualTree đã bắt đầu cuộn? và liên tiếp đặt IsDropDownOpen = false?

+0

Tôi có cùng một câu hỏi và vấn đề. Tôi cuộn lưới của tôi và cửa sổ bật lên của tôi với các hoạt động tùy chỉnh ở trên cùng một vị trí! Tôi cần phải di chuyển popup với lưới! – Evgeny

Trả lời

10

Chúng tôi có thể viết trình kích hoạt để sử dụng với các thành phần có trong một ScrollViewer. Đây là một ứng dụng mẫu hoàn chỉnh:

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

Chúng tôi có một nút mở ra một Popup và bất kỳ di chuyển trong bất kỳ cha mẹ ScrollViewer làm cho ScrollTrigger hành động bắn và sau đó chúng ta có thể đóng cửa sổ bật lên. Lưu ý rằng trình kích hoạt được gắn vào Button và không phải là Popup. Chúng ta có thể sử dụng bất kỳ phần tử lân cận nào có trong cây thị giác. Cũng lưu ý rằng chúng tôi sử dụng trình kích hoạt khác để mở Popup nhưng cách mở nó không quan trọng đối với câu hỏi ban đầu.

Đây là 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; 
    } 
} 

Các ScrollTrigger là rất đơn giản, nó chỉ gắn cho tất cả các mẹ ScrollChanged sự kiện và bắn bất cứ hành động kiềm chế. Trong mẫu, chúng tôi sử dụng ChangePropertyAction để đóng Popup.

Nếu bạn không quen thuộc với các hành vi, cài đặt Expression Blend 4 SDK và thêm các không gian tên:

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

và thêm System.Windows.InteractivityMicrosoft.Expression.Interactions để dự án của bạn.

1

Tôi không hoàn toàn hình dung mức độ kiểm soát của bạn, nhưng bạn có thể căn cứ vào việc mở/đóng điều khiển trên sự kiện Focus không? Và nếu nó mất tập trung, để đóng cửa sổ bật lên? Có thể tôi hiểu sai, bạn có thể đăng đoạn mã không? Daniel