Microsoft MVP성태의 닷넷 이야기
Mouse이벤트 관련해서 질문있습니다. [링크 복사], [링크+제목 복사]
조회: 20616
글쓴 사람
이성환 (vactorman at naver.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)

다른 플랫폼에서 해보진 않아서 잘 모르겠습니다만

WPF에서 Mouse 관련 이벤트들이 예상과 다르게 동작하는 것이 있어서 질문드립니다.

예를 들어 Rectangle에 MouseEnter / Leave / Up / Down 이벤트 핸들러를

Preview와 함께 모두 연결했습니다.

그랬을 때 Rectangle을 한 번 클릭하면

Preview Mouse Left Button Down
Preview Mouse Down
Mouse Left Button Down
Mouse Down
Preview Mouse Left Button Up
Preview Mouse Up
Mouse Left Button Up
Mouse Up

뭐 이런 순서로 이벤트가 발생할 거라고 예상 하는데요.




네. 예상대로 잘 발생합니다.



그런데

Rectangle을 Button의 자식. 그러니까 Button의 Content로 넣은 후

다시 클릭하면



Preview Mouse Left Button Down
Preview Mouse Down
Mouse Left Button Down
Mouse Down
Mouse Leave

(이 시점에서 Mouse Up 했습니다.)
Mouse Enter



이렇게 이벤트가 발생합니다.

문제는 Rectangle에 걸어놨던 MouseUp이벤트 들이 하나도 발생하지 않는다는 것이죠.

또 저 MouseLeave가 발생하는 시점에서 Rectangle의 IsMouseOver 값을 확인하면 false가 나옵니다.

Mouse Down 상태에서 MouseLeave 이벤트가 발생한 것도 이상한데

마우스 포인터가 Rectangle을 벗어나지 않았음에도 IsMouseOver가 false로 나오는 것 역시 이해가 잘 안 됩니다.


그런데 더 이상한 건

Rectangle의 PreviewMouse 이벤트 핸들러에서 Break Point를 걸고 다시 테스트 하면

위와 다른, 정상적인 결과 (처음 예상했던 결과)가 나옵니다.

결과가 이상해서 추가한 Button에도 동일하게

PreviewMouseLeftButtonDown, PreviewMouseLeftButtonUp, PreviewMouseDown, PreviewMouseUp, MouseDown, MouseUp, MouseEnter, MouseLeave

그리고 Click 이벤트 핸들러를 연결하고 다시 테스트 해보니

Button의 PreviewMouseLeftButtonDown, PreviewMouseDown, MouseDown 이벤트들이 발생하지 않았습니다.
(물론 Button의 자식으로 들어가 있는 Rectangle은 앞서 언급한 비정상적인 결과와 동일했습니다.)

가장 마지막에 발생한 이벤트는 Click 이벤트였습니다.


제가 WPF의 Mouse 이벤트에 대해 이해를 잘못 하고 있는 건지

원래 이런 건지 잘 모르겠습니다.

당장 필요한 건 MouseUp 이벤트를 받는 건데 어떻게 해야할 지 감이 안 잡힙니다.


혹시나 해서 간단한 테스트 솔루션하나 첨부해볼게요.

확인 부탁드립니다.



[연관 글]






[최초 등록일: ]
[최종 수정일: 7/13/2011]


비밀번호

댓글 작성자
 



2011-07-13 05시40분
[이성환] 아.. 수정하다 실수로 파일이 두개가 돼 버렸네요. 둘 다 같은 파일 입니다. 하나만 보시면 될듯...
[guest]
2011-07-15 08시23분
[이성환] 혼자 이것저것 테스트 해보면서 어설프게나마 결론에 도달했습니다.

Button 내부의 Element들에게서 MouseLeaver가 발생하는 이유는

Button의 MouseDown 이벤트가 도착할 때 Button 스스로 CaptureMouse를 하기 때문이더군요.

비단 Button 뿐만 아니라 자식을 가진 Element의 경우에도 마찬가지로

부모가 CaptureMouse를 하면 그 순간 자식들에게 모두 MouseLeave 이벤트가 떨어졌습니다.

당연히 MouseLeave 이후 MouseEnter나 MouseDown이 일어나지 않았으니 MouseUp 역시 발생하지 않은 거구요.

Button 이 CaptureMouse를 하는 지는 이번에 처음 알았습니다.

어쩔 수 없이 MouseUp을 대체하는 방법으로 돌고 돌아서 MouseUp과 유사한 형태의 이벤트 처리를 하긴 했지만

생각보다 사소하다고 여겼던 것에 한 번 당하고 나니

이벤트 처리, 특히 마우스 관련 처리는 한 번 더 고민하고 사용하게 됐네요.

[guest]
2011-07-15 08시25분
[이성환] 근데 궁금한 건.

왜 Button에는 버블링 MouseDown / Up 이벤트가 발생하지 않을까요?

암만 찾아봐도 PreviewMouseDown / Up 까지는 들어오는데 버블링 MouseDown / Up 이벤트는 발생하지 않네요.

왜 그런건가요??
[guest]
2011-07-18 07시28분
제가 WPF 손을 놓은지 꽤나 오래 되어서 ^^ 관련 지식도 희미해지는 바람에 답변이 너무 늦었습니다.

일단, 이벤트 버블링과 터널링이 있는데요.

WPF Input Events
; https://docs.microsoft.com/en-us/dotnet/desktop/wpf/advanced/routed-events-overview#how_event_processing_works

버블링은 부모 요소로 이벤트를 전달하는 것이기 때문에 "Button에서 버블링이 왜 안되느냐"는 질문은 올바르지 않습니다. ^^ Button의 하위 요소인 Rectangle에 이벤트가 내려가는 것이므로 Tunneling이 왜 안되냐가 맞습니다.

이성환 님이 직접 살펴보신 대로, 아마도 마우스의 캡처가 원인이지 않을까 싶습니다. ^^ Win32 시절부터 윈도우 영역을 벗어나는 경우에도 마우스 이벤트를 유지해야 하는 경우 SetCapture/ReleaseCapture 함수를 호출하는 동작이 있었습니다.

버튼의 경우, 마우스를 누른 체로 윈도우 영역을 벗어나도 여전히 마우스가 캡처된 상태이기 때문에 다시 누른 체로 마우스를 버튼 위로 이동해서 버튼을 떼면 Click 이벤트가 발생하게 됩니다. 즉, 다른 요소보다는 특별한 동작이 요구되는데, 이러한 처리 때문에 이벤트 터널링에 영향이 있는 것 같습니다.

일단 현상이 그러하니, 다른 방법을 찾아야 할 텐데 터널링이 안 되므로 자식 요소에서 직접 부모 요소의 Up 이벤트를 감시하는 방법이 어떨까 싶습니다. 이를 위해 버튼이 버블링해 주는 Up 이벤트를 가로채면 되겠지요. ^^

xButton.AddHandler(MouseUpEvent, new MouseButtonEventHandler(mouseUpEvent), true);

어쨌든, 이성환 님 덕분에 저도 버튼의 이벤트 처리에 대한 생각을 다시 해 볼 수 있게 되었군요. ^^

(참고로, 마지막 질문에서 헷갈리신 것 같은데 PreviewMouseDown/MouseDown은 잘 들어오는데, PreviewMouseUp/MouseUp이 안되는 것입니다. ^^)
정성태
2011-07-18 09시20분
[이성환] 답변 감사드립니다. (__)

그런데.. 제가
왜 Button에는 버블링 MouseDown / Up 이벤트가 발생하지 않을까요? 라고 질문했던 건

xButton의 MouseDown/Up 이벤트가 발생하지 않는다는 의미였습니다.

실제로 Output을 찍어보면

xButton_MouseEnter Button Captured : False
xRootGrid_MouseEnter Button Captured : False
xMainRectangle_MouseEnter Button Captured : False
== 요기까지는 클릭을 위해 MouseEnter 되는 시점.

== 요기서부터 MouseLeftButtonDown
xRootGrid_MouseLeave Button Captured : False
xButton_PreviewMouseDown Button Captured : False
xRootGrid_PreviewMouseLeftButtonDown Button Captured : False
xRootGrid_PreviewMouseDown Button Captured : False
xMainRectangle_PreviewMouseLeftButtonDown Button Captured : False
xMainRectangle_PreviewMouseDown Button Captured : False
xMainRectangle_MouseLeftButtonDown Button Captured : False
xMainRectangle_MouseDown Button Captured : False
xRootGrid_MouseLeftButtonDown Button Captured : False
xRootGrid_MouseDown Button Captured : False
xMainRectangle_MouseLeave! Button Captured : True
xRootGrid_MouseLeave Leave Button Captured : True
== 요기까지가 MouseLeftButtonDown 후 그대로 유지 상태.

== 요기서부터 MouseUp
The thread '<No Name>' (0x880) has exited with code 0 (0x0).
xButton_PreviewMouseLeftButtonUp Button Captured : True
xButton_PreviewMouseUp Button Captured : True
xMainRectangle_MouseEnter Button Captured : False
xRootGrid_MouseEnter Button Captured : False
xButton_Click Button Captured : False

요런 형태 인데요.

보시다 시피

xButton_PreviewMouseDown
xButton_PreviewMouseLeftButtonUp
xButton_PreviewMouseUp
xButton_Click 까지는 발생하고

나머지 버블링 관련 이벤트들은 하나도 발생하지 않았는데요. (당연히 핸들러는 다 걸려있구요.)

왜 xButton에 버블링 이벤트가 하나도 발생하지 않았는지는 아직 답을 찾지 못해서 질문드린 것이었습니다.
(그러고 보니 xButton_PreviewLefrButtonDown도 발생하지 않았네요..)

요거까지 확인을 해야 시원하게 원인파악을 했다고 말할 수 있을 것같아서요...;ㅅ;
[guest]
2011-07-18 09시42분
아래의 글에 별도로 답변을 달았으니 참고하세요. ^^

왜? Button 컨트롤에는 MouseDown/MouseUp 이벤트가 발생하지 않을까요?
; http://www.sysnet.pe.kr/2/0/1089

그리고, 마지막 댓글에서 xButton_PreviewLeftButtonDown도 발생하지 않는다고 쓰셨는데... 발생합니다. 왜 발생하지 않은 듯(?) 보인 것인지, 다시 한번 소스 코드를 점검해 보세요. ^^
정성태
2011-07-18 11시01분
[이성환] 매번 친절한 답변 감사드립니다.

근데 제가 우매하여... 아직도 이해가 되질 않습니다.

일단 제가 첨부한 소스에서는 e.Handled = true; 가 없습니다.
(요건 알고 있던 거라..)

그런데 저는 제가 첨부한 소스로 해봐도, 제가 테스트 하던 소스로 해봐도

역시 xButton의 버블링 이벤트는 발생하지 않습니다.
(xButton_PreviewMouseLeftDown 역시 발생하지 않습니다.)

이벤트 전달을 막은 곳도 없고
(e.Handled = true로 막았다고 이벤트가 전달 안 되는 건 아니니까 더 이상합니다.)

해당 이벤트의 핸들러가 등록되어있지 않은 것도 아닌데

포스팅 해주신 글을 몇 번 읽어봐도

왜 이벤트가 발생 안 하는지 모르겠습니다.
(정확히는 왜 핸들러를 호출하지 않는 건지)

혹시 같은 소슨데 저만 안 되는 건가요??

;ㅅ;
[guest]
2011-07-18 11시03분
[이성환] 아.. PreviewMouseLeftDown 은 Output을 잘못 찍고 있었군요...

이건 찾았습니다...;;;

그럼 xButton의 버블링 이벤트만 확인하면 되겠군요....;;;
[guest]
2011-07-19 12시34분
음... ^^ 제가 쓴 글은, WPF의 Button 컨트롤도 같은 방식으로 되어 있다는 것을 설명해 드린 것입니다. .NET Reflector로 버튼 쪽 소스를 보면 MouseLeftButtonDown 이벤트에서 e.Handled = true를 걸고 있기 때문에 Bubbling이 발생하지 않는 것입니다.
정성태
2011-07-19 08시54분
[이성환] 아.. 그렇군요. Button 내부에서 이미 e.Handled = true 처리를 하고 있어서

버블링 이벤트가 발생 안 하는 것이었군요. ;;;;

포스팅에서 링크 걸어 놓으신 social 게시판에서도 질문자가 저와 동일한 질문을 한 번 더 했고

그 다음 답변에 Snoop을 써서 이벤트 구조를 확인해보라는 걸로 마무리가 나 있길래

이거 그냥은 모르는 거구나 했습니다.

그리고 제가 아직 그 정도까지 Reflector를 잘 쓰질 못해서 내부 소스 보는 게 꺼려지더군요.

이 기회에 공부 좀 해야겠습니다.

덕분에 많이 배웠습니다. ~ㅂ~

매번 좋은 글과 답변 주셔서 감사합니다 (__)
[guest]

... 16  17  18  19  20  21  [22]  23  24  25  26  27  28  29  30  ...
NoWriterDateCnt.TitleFile(s)
5372민성8/24/20207586안녕하세요 WPF 웹브라우저 컨트롤에서 웹브라우저 자체를 엣지로 할 수가 있나요? [2]
5371서현준8/11/20206611Hyper-V 내부 네트워크 환경 중, VM 에서 인터넷 접속 [1]
5370독자8/11/20205660.net createobject 관련 질문입니다.. [4]
5369독자8/10/20205988c# 8.0 프로그래밍 책에 대한 질문 드립니다 [1]
5368guest8/10/20207278시작하세요! C# 8.0 프로그래밍 책에 오타가 있습니다. [1]
5367박순기8/8/20206194디버깅 시 반전되는 부분 글 색상이나 배경색을 변경하는 방법 [3]파일 다운로드1
5366간절함8/7/20206887하나의 솔루션에서, 32비트 프로젝트에서 다른 64비트 프로젝트 참조하는 방법 궁금합니다. [4]
5365영귤8/6/20206133TimeSpan 구할 때 시간대를 바꿔도 같은 값이 나오는 것 같습니다. [1]
5364박순기8/5/20206184visual studio의 menu bar font size 변경방법 문의 [2]파일 다운로드1
5363클락8/1/20206805c# 9.0 출간 준비 중이신가요? [2]
5361하태7/29/20206423안녕하세요! 바이너리데이터 파싱 질문 드리겠습니다!. [2]
5360진우7/28/20207389엑셀에서 발생하는 모든 이벤트를 감지 할수 있는지 궁금합니다. [6]파일 다운로드1
5358홍길동7/22/20206097개체에서 open 속성이나 매서드가 지원 되지 않읍니다.라고 오류창이 뜨는데. [1]
5357손동섭7/22/20206170책 예제코드... [3]
5355neska7/21/20206554안녕하세요 문의 드립니다 [1]
5354민성7/15/20208017안녕하세요 db연결 문자 보안 [2]
5353형성재7/14/20207056Visual Studio Setup Project에서 VC++2010재배포패키지설치 [4]
5352윤식7/10/20207060닷넷코어 빌드 시 runtimeconfig 파일을 없앨 수 있는지.. [4]
5351runr...7/2/20206908C# 에서 C++ dll 병렬 사용 [1]
5350홍성호6/29/20208525C++에서 정의된 구조체(공유메모리)를 C#으로 공유메모리에서 구조체 변환시 에러가 발생 합니다. [1]파일 다운로드1
5349jero...6/24/20206045logon credential provider 관련 문의드립니다. [1]
5348776/19/20205775시작하세요 C# 8.0프로그래밍 책에 대한 질문입니다. [8]
5347민성6/19/20206599안녕하세요 WPF Binding에서요 [1]
5346dimo...6/18/20206645Task.WhenAll() 메소드를 이용한 코드를 좀더 짧게 사용하고 싶은데 다른 표현이 있을까요? [3]
5345질문요6/12/20205755idc vs 집 속도 [2]
5344하태6/2/20206886c++ .ilb에서 c# dll 호출 질문 드리겠습니다 (콜백함수 전달) [4]
... 16  17  18  19  20  21  [22]  23  24  25  26  27  28  29  30  ...