Microsoft MVP성태의 닷넷 이야기
Mouse이벤트 관련해서 질문있습니다. [링크 복사], [링크+제목 복사]
조회: 20727
글쓴 사람
이성환 (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]

1  2  3  4  5  6  [7]  8  9  10  11  12  13  14  15  ...
NoWriterDateCnt.TitleFile(s)
5781List맨1/5/20233794List.Add("newobj") 속도는 빠른 편인지요? [11]
5780임세1/3/20234410C# 프로그래밍 10 책 구매한 사람입니다. 3부 자료는 어디서 다운 받을 수 있나요? [4]
5779이건우1/2/20233287안녕하십니까 루프안에서 메세지처리에 관하여 질문드립니다! [2]
5778이건우12/30/20224555안녕하세요 c#에서 dll참조 관련 질문드립니다. [4]
5777감사합니...12/29/20223558UI Thread에 Invoke 처리관련 궁금합니다. [3]
5776pdf맨12/28/20223355C# MouseUp Event + pdf [10]
5775민성12/28/20223138안녕하세요 Class 관련해서 예외처리를 하나로 받아낼수 있는 방법 [1]
5774중급12/27/20223933중급개발자란 어느 수준인지요? [4]
5773김영식12/26/20223460c# 압축파일 읽어 올 때 BinaryRead 한글 처리 문제 [1]
5772눈송이12/26/20223593Excel VSTO 는 왜 Net Core, Net 5, 6 버전을 사용하지 않나요? [2]
5771김훈12/26/20223696c# .net client application 망분리(내부망,외부망) 환경에서 의문의 외부사이트 호출 대기 [2]
5770lsh12/26/20223302클라우디움안에 있는 파일을 File.Copy 하고싶은데 코드로는 접근을 못하나요? [1]
5769울타리12/20/20223340Active Directory 2012R2 2016 또는 2019 마이그렝션 문의 드립니다. [1]
5768c++12/14/20224091Thread를 사용한 C++ DLL에 관련된 질문입니다. [6]파일 다운로드2
5767민성12/9/20223441안녕하세요 ashx로 화일을 저장하고 화일명을 리턴하는데요 [1]
5766김명훈12/9/20223590웹브라우저에서 묻지 않고 바로 다운로드 [2]
5765hong12/1/20223833Winform(.Net6) 클라이언트에서 SignalR Core 웹서버에 접속시 인증서 문제 [3]파일 다운로드1
5764요한11/30/20224037c++ 동일한 객체인지 비교 방법문의 [2]
5763고필석11/30/20223556시작하자마자 비정상 종료하는 프로세스에 대한 문제 해결 조언 요청 드립니다. [3]
5762흰털너부리11/30/20223538wpf mvvm ui update 로딩중 표시 [1]
5761민성11/29/20223439죄송하지만 한가지만 더 여쭈어 보겠습니다 [1]
5760민성11/29/20223362안녕하세요 [2]
5759문정환11/28/20223713c# socket 통신할때 빅엔디언으로 바꿔줘야 하나요? [1]
5758라떼11/28/20224906Linux 에서 winform UI 어플리케이션 실행하기 [3]
5757흰털너부리11/25/20223863asp.net core EF AddDbContext,AddDbContextFactory 차이점 알려주세요 [1]
5756흰털너부리11/25/20223438asp.net core web api에서 json 특정 property 무시하는 방법 문의 드립니다. System.Text.Json 사용중입니다. [1]
1  2  3  4  5  6  [7]  8  9  10  11  12  13  14  15  ...