2009-04-11 25 views
5

Tôi đang xây dựng một điều khiển vải. Canvas gốc này có một số trẻ chồng chéo (canvas). Điều này được thực hiện để mỗi đứa trẻ có thể xử lý bản vẽ của riêng mình và sau đó tôi có thể soạn kết quả cuối cùng với bất kỳ sự kết hợp nào của trẻ em để có được hành vi mong muốn.Điều khiển chồng chéo C# wpf không nhận sự kiện chuột

Điều này đang hoạt động rất tốt khi hiển thị có liên quan. Điều này không hoạt động tốt như vậy với các sự kiện chuột tuy nhiên. Các sự kiện cách chuột công trình như sau (sử dụng previewmousemove là một ví dụ):

1- Nếu gốc vải đang được chuột, sự kiện cháy 2- Kiểm tra tất cả trẻ em, nếu một người đang bị chuột, sự kiện cháy và ngăn chặn

Như vậy, chỉ con đầu tiên tôi thêm sẽ nhận được sự kiện di chuyển chuột. Sự kiện này không được tuyên truyền cho tất cả trẻ em vì chúng chồng lên nhau.

Để khắc phục điều này, tôi đã cố gắng như sau: sự kiện chuột 1- Override trong canvas gốc 2- Đối với mỗi sự kiện, tất cả trẻ em mà muốn để xử lý các sự kiện sử dụng VisualTreeHelper.HitTest 3 Đối với tất cả trẻ em trả về một kết quả kiểm tra hit hợp lệ (ví dụ: dưới chuột và sẵn sàng xử lý sự kiện (IsHitTestVisible == true)), ???

Đây là nơi tôi bị kẹt, bằng cách nào đó tôi cần gửi sự kiện chuột cho tất cả trẻ em và dừng lưu lượng thông thường của sự kiện để đảm bảo đứa trẻ đầu tiên không nhận được hai lần (thông qua xử lý = true trong biến cố).

Bằng cách sử dụng RaiseEvent với cùng một sự kiện được truyền cho trẻ em, mọi thứ dường như hoạt động nhưng bằng cách nào đó nó cũng làm tăng sự kiện trên bố cục gốc (canvas gốc). Để bỏ qua điều này, tôi cần tạo một bản sao của sự kiện và thiết lập lực lượng đặt nguồn mặc dù nó dường như có nhiều hack hơn là một giải pháp. Có cách nào thích hợp để làm những gì tôi đang cố gắng làm không? Ví dụ mã sau.

public class CustomCanvas : Canvas 
    { 
     private List<object> m_HitTestResults = new List<object>(); 

     public new event MouseEventHandler MouseMove; 

     public CustomCanvas() 
     { 
      base.PreviewMouseMove += new MouseEventHandler(CustomCanvas_MouseMove); 
     } 

     private void CustomCanvas_MouseMove(object sender, MouseEventArgs e) 
     { 
// Hack here, why is the event raised on the parent as well??? 
      if (e.OriginalSource == this) 
      { 
       return; 
      } 

       Point pt = e.GetPosition((UIElement)sender); 
       m_HitTestResults.Clear(); 

       VisualTreeHelper.HitTest(this, 
        new HitTestFilterCallback(OnHitTest), 
        new HitTestResultCallback(OnHitTest), 
        new PointHitTestParameters(pt)); 

       MouseEventArgs tmpe = new MouseEventArgs(e.MouseDevice, e.Timestamp, e.StylusDevice); 
       tmpe.RoutedEvent = e.RoutedEvent; 
       tmpe.Source = this; 

       foreach (object hit in m_HitTestResults) 
       { 
        UIElement element = hit as UIElement; 
        if (element != null) 
        { 
// This somehow raises the event on us as well as the element here, why??? 
         element.RaiseEvent(tmpe); 
        } 
       } 


      var handlers = MouseMove; 
      if (handlers != null) 
      { 
       handlers(sender, e); 
      } 

      e.Handled = true; 
     } 

     private HitTestFilterBehavior OnHitTest(DependencyObject o) 
     { 
      UIElement element = o as UIElement; 
      if (element == this) 
      { 
       return HitTestFilterBehavior.ContinueSkipSelf; 
      } 
      else if (element != null && element.IsHitTestVisible && element != this) 
      { 
       return HitTestFilterBehavior.Continue; 
      } 
      return HitTestFilterBehavior.ContinueSkipSelfAndChildren; 
     } 

     private HitTestResultBehavior OnHitTest(HitTestResult result) 
     { 
      // Add the hit test result to the list that will be processed after the enumeration. 
      m_HitTestResults.Add(result.VisualHit); 
      // Set the behavior to return visuals at all z-order levels. 
      return HitTestResultBehavior.Continue; 
     } 
+0

Lưu ý rằng tôi cũng sẽ cần điều này để làm việc với chú giải công cụ bên trong trẻ em của trẻ em trong canvas gốc. –

+1

Đây có phải là thiết bị cho Silverlight không? WPF? Thêm các thẻ có liên quan, bạn sẽ nhận được câu trả lời nhanh hơn. – SirDemon

Trả lời

0

Tôi thấy ví dụ mã của bạn thú vị nên tôi đã thử ... nhưng tôi phải thực hiện một sửa đổi nhỏ để nó hoạt động đúng cách trong nội dung của tôi.

tôi đã phải thay đổi thứ 2 "nếu" trong phương pháp HitTestFilter như sau:

if (element == null || element.IsHitTestVisible) 

Như bạn có thể thấy tôi gỡ bỏ vô dụng "! Element = này" ở cuối (bạn đã kiểm tra điều kiện trong "if" đầu tiên và tôi đã thêm "element == null" vào đầu.

Tại sao? Bởi vì tại một số thời điểm trong quá trình lọc kiểu tham số là System.Windows.Media.ContainerVisual không thừa hưởng từ UIElement và vì vậy phần tử sẽ được đặt thành null và ContinueSkipSelfAndChildren sẽ được trả về. Nhưng tôi không muốn bỏ qua các con vì Canvas của tôi được chứa bên trong bộ sưu tập "Trẻ em" của nó và các UIElements mà tôi muốn hittest được chứa trong Canvas.

3

Tôi nghĩ bạn nên sử dụng các sự kiện xem trước vì những sự kiện này là RoutingStrategy.Tunnel từ Cửa sổ đến điều khiển cao nhất trong Z-Order và các sự kiện bình thường là RoutingStrategy.Bubble.

Trong RoutedEvents này có một thuộc tính Xử lý khi đúng, hệ thống sẽ dừng lại để duyệt qua cây thị giác vì ai đó đã sử dụng sự kiện này.

0

Giống như @GuerreroTook đã nói, bạn nên giải quyết vấn đề này bằng cách sử dụng RoutedEvents của WPF (xem thêm thông tin here.

Các vấn đề liên quan