Microsoft MVP성태의 닷넷 이야기
Mouse이벤트 관련해서 질문있습니다. [링크 복사], [링크+제목 복사]
조회: 13663
글쓴 사람
이성환 (vactorman at naver.com)
홈페이지
첨부 파일
다른 플랫폼에서 해보진 않아서 잘 모르겠습니다만

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 이벤트를 받는 건데 어떻게 해야할 지 감이 안 잡힙니다.


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

확인 부탁드립니다.



[연관 글]


donaricano-btn



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


비밀번호

댓글 쓴 사람
 



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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

WPF Input Events
; http://msdn.microsoft.com/en-us/library/ms742806.aspx#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도 발생하지 않았네요..)

요거까지 확인을 해야 시원하게 원인파악을 했다고 말할 수 있을 것같아서요...;ㅅ;

[손님]
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로 막았다고 이벤트가 전달 안 되는 건 아니니까 더 이상합니다.)

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

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

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

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

;ㅅ;

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

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

그럼 xButton의 버블링 이벤트만 확인하면 되겠군요....;;;
[손님]
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를 잘 쓰질 못해서 내부 소스 보는 게 꺼려지더군요.

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

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

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

... 31  32  33  34  [35]  36  37  38  39  40  41  42  43  44  45  ...
NoWriterDateCnt.TitleFile(s)
1524임종복1/4/20157200    답변글 [답변]: windows 2008 r2에서 ms-sql 2008 서버사용시 tls문제점 [2]
1521윤대욱12/19/20146009C++ 에서 서버와 클라이언트를 나누어서 구조체 전달에 대해서 궁금합니다. [1]파일 다운로드1
152012/10/20145629datetime관련해서요 [1]
1516aTo12/1/20146191wpf 배포관련. [3]
1514얄미운제리11/17/20146593[C# Mono]Mono Chart 개발 문의드립니다. [1]
1355미나리나물11/13/20145338RDP 접속 방식 질문드리고 싶습니다. [1]
1353송용국11/10/20144754TeamFoundationServer 에 소스를 Target서버로 옮기는(내려주는) 방법 있나요? [1]
1351bluetroll11/7/20148443c# webbrowser 모바일환경 접속 [1]
1350에메11/7/20146614WCF namedpipe 퍼블리싱 충돌 문제 [3]파일 다운로드1
1349Chun Hojun11/6/201411758Microsoft. Net Framework 액세스 거부 오류...... [2]
1348김준석11/6/20147969 Mini dump 기록 안되는 현상 [2]파일 다운로드1
1346개미11/5/201420546https페이지에서 http서버에 있는 이미지 파일 호출시 보안 오류 [8]
1345장구니11/4/20146295AWS 인스턴스를 만들었는데 [1]
1343h11/2/20146205안녕하세요 [1]
1342왕초보11/1/201410958C#에서의 함수포인터 [5]
1347왕초보11/5/20146799    답변글 [답변]: C#에서의 함수포인터 [1]
1341영택10/29/20147441MFC Amazon S3 사용관련하여 질문드립니다. [2]
1344영택11/4/20145087    답변글 [답변]: MFC Amazon S3 사용관련하여 질문드립니다. [2]
1340감사합니다10/28/20148831c# wpf shdocvw internet explorer를 윈도우프레임으로 집어 넣을 수 있는지 궁금합니다. [3]파일 다운로드1
1338헬프미10/28/20149160tcp 소켓의 SYN_RECV 상태에 대하여 질문있습니다. [4]
1336이소정10/27/20145632filestream seek에 대해 질문있습니다. [1]
1337이소정10/28/20145507    답변글 [답변]: filestream seek에 대해 질문있습니다.파일 다운로드1
1339이소정10/28/20148259        답변글 [답변]: [답변]: filestream seek에 대해 질문있습니다. [2]파일 다운로드2
1335황지혜10/24/20147403psexec 관련 질문드립니다. [1]
1334dell10/24/20145193여기가 있는줄 모르고 방명록에 남겼네요 ㅠㅠ 방명록 한번만 봐주시면 안될지요? [1]
1333왕초보10/24/20146030Bitmap 질문 [5]
... 31  32  33  34  [35]  36  37  38  39  40  41  42  43  44  45  ...