2009-04-11 2 views
5

캔버스 컨트롤을 작성 중입니다. 이 루트 캔버스에는 여러 개의 겹치는 하위 항목 (캔버스)이 있습니다. 이것은 각 어린이가 자신의 그림을 다룰 수 있도록하기 위해 수행되며 원하는 동작을 얻기 위해 자녀의 조합으로 최종 결과를 작성할 수 있습니다.wpf wpf 컨트롤이 겹쳐서 마우스 이벤트를받지 못했습니다.

이것은 렌더링과 관련하여 매우 잘 작동합니다. 그러나 마우스 이벤트에서는 잘 작동하지 않습니다. 방법 마우스 이벤트 작품 (예를 들어 previewmousemove 사용) 다음과 같습니다 : 하나의 마우스, 화재 이벤트 중에 있으며

을 중지하면 루트 캔버스, 마우스, 화재 이벤트 2 체크 모든 어린이 아래

1 경우

이와 같이, 내가 추가 한 첫 번째 자식 만 마우스 이동 이벤트를 수신합니다. 이벤트는 겹치기 때문에 모든 하위 항목에 전달되지 않습니다.

는이 문제를 극복하기 위해, 나는 다음과 같은 시도 : 모든 어린이를위한 VisualTreeHelper.HitTest 3를 사용하여 이벤트를 처리 할 모든 아이들을 찾아, 루트 캔버스 모든 이벤트에 대한 2에서 1 무시 마우스 이벤트를이 유효한 히트 테스트 결과를 반환했습니다 (예 : 마우스 아래에서 이벤트를 처리하고자하는 경우 (IsHitTestVisible == true))?

이것은 내가 붙어있는 곳입니다. 어떻게 든 마우스 이벤트를 모든 자식에게 보내고 첫 번째 자식이 두 번받지 못하도록 이벤트의 일반적인 흐름을 중지해야합니다. 행사).

동일한 이벤트가 전달 된 RaiseEvent를 사용하면 모든 것이 작동하는 것처럼 보이지만 어쨌든 부모 (루트 캔버스)에서도 이벤트가 발생합니다. 이것을 우회하려면 이벤트 복사본을 만들고 강제 설정을 통해 소스를 설정해야했지만 솔루션보다 해킹 된 것으로 보입니다. 내가하려는 일을하는 적절한 방법이 있습니까? 코드 예는 다음과 같습니다.

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

루트 캔버스 하위의 하위에있는 툴팁을 사용하려면이 기능이 필요합니다. –

+1

실버 라이트 용입니까? WPF? 관련 태그를 추가하면 더 빨리 답변을 얻을 수 있습니다. – SirDemon

답변

0

재미있는 코드 예제를 발견하여 시도해 보았습니다. 그러나 제 물건을 올바르게 수정하려면 약간 수정해야했습니다. 당신은 내가 쓸모 제거 볼 수 있듯이

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

가! "요소 =이"마지막에 (이미 해당 조건을 테스트 :

나는이 (가) 2 "가"다음과 같은 HitTestFilter 방식으로 변경했다 첫 번째 "if"에서) 그리고 "element == null"을 처음에 추가했습니다.

왜? 필터링 중에는 매개 변수 유형이 System.Windows.Media.ContainerVisual이고 UIElement에서 상속되지 않으므로 element는 null로 설정되고 ContinueSkipSelfAndChildren이 반환됩니다. 그러나 Canvas가 "Children"컬렉션에 포함되어 있고 내가 치고 싶은 UIElements가 Canvas에 포함되어 있기 때문에 아이들을 건너 뛰고 싶지 않습니다.

3

Window에서 RouteStrategy.Tunnel, Z-Order의 가장 높은 컨트롤까지 RoutingStrategy.Bubble이므로 미리보기 이벤트를 사용해야한다고 생각합니다.

이 RoutedEvents에는 누군가가이 이벤트를 사용했기 때문에 시스템이 시각적 트리를 가로 지르는 것을 중지 할 속성 Handle이 있습니다.

0

@GuerreroTook과 마찬가지로 WPF의 RoutedEvents (자세한 정보는 here)를 사용하여이 문제를 해결해야합니다.