WPF 강의 섹션 3. WPF#SUB(심화 과정)
WPF는 WinForms와 달리 GPU를 적극적으로 사용하기 때문에 GPU를 갖춘 컴퓨터, 서버를 이용하면 WinForms보다 더 나은 속도를 보장할 수 있다.
-그래픽 카드에게 그래픽 관련(화면 그리는 요소)을 시키고 CPU에는 계산 작업에 더욱 집중할 수 있기 때문에 좋은 성능을 발휘할 수 있다.
그러나 가정용 컴퓨터가 아닌 납작한 컴퓨터(서버 그래픽카드)는 일반 그래픽 카드보다 매우 비싸기 때문에 주의 해야한다.
만약 서버에 GPU 없이 CPU만 있다면 WinForms와 마찬가지로 CPU가 화면을 그리는 요소의 일까지 담당하게 된다.
화면을 다시 그릴 때 프로그램이 버거워 하면 데이터를 실시간으로 반영하는 것 보다 Que, List, Dictionary를 사용하여 일정 시간간격으로 데이터를 반영하는 방법이 더 좋을 수 있다.
새 프로젝트를 생성하여 화면에 Button과 Label을 추가하고 Button과 Grid에 MouseDown 이벤트로 Label의 내용을 덧붙이는 코드를 작성했다.
Button의 MouseDown 이벤트는 Label에 "버튼"이라는 내용을 덧붙이고 Grid의 MouseDown 이벤트는 Label에 "Grid"이라는 내용을 덧붙인다.
예상대로라면 실행 후 Button을 눌렀을 때엔 Label에 "버튼"을 덧붙여 'Label버튼'이 되어야 하는데 실제로 화면에 보이는 것은 'Label버튼Grid'로 Grid의 MouseDown 이벤트까지 같이 동작했다. 그 이유는 무엇일까?
Grid를 클릭했을 때 Label에 Grid라는 내용이 덧붙여진 화면
Button을 클릭했을 때 Label에 버튼Grid가 덧붙여진 화면
프로그램 실행 후 상단 왼쪽의 '라이브 시각적 트리로 이동'을 클릭하면
솔루션 탐색기가 위치했던 자리에 라이브 시각적 트리가 보이는데 Button의 Parent 요소(상위 요소)가 Grid라는 것을 알 수 있다. (Grid의 상위 요소는 MainWindow이다.)
즉 WPF에서는 기본적으로 Event가 상위 요소로 Routing(전달)이 된다는 것이다.
Button도 Grid도 MouseDown 이벤트를 수신하기 때문에 두 개의 내용이 전부 다 표시 된 것인데 이벤트를 발생시킨 Button에서 먼저 수신하고 다음 상위 요소인 Grid로 전달하는 형태가 된다.
WPF의 Routed Event는 다음과 같이 세 가지 Strategies 중 하나에 속한다.
1. Bubbling Event(Bubbling Routing Strategy)
- Event 발생 지점에서 시작하여 최상위 root까지 전달.
2. Tunneling Event(Tunneling Routing Strategy)
- 최상위 root에서 시작하여 Event 발생 지점까지 전달.
- event 이름에 preview로 시작하는 것이 특징.
3. Direct Event(Direct Routing Strategy)
- MouseEnter(Bubbling), PreviewMouseDoubleClick(Tunneling) 이벤트가 여기에 속한다.
- 실제로는 Bubbling Event, Tunneling Event로 동작하는 경우가 많다.
Button과 Grid 이벤트 함수 목록을 보면 앞이 Preview로 되어있는 것들이 있다.
아까와 마찬가지로 Button과 Grid에 PreviewMouseDown 이벤트 함수로 Label에 문자열을 덧붙이는 코드를 작성한다.
Button은 "previewBtn"을 덧붙이고 Gird는 "previewGrid"를 덧붙인다.
실행해보면 다음과 같이 Button을 클릭하면 Label에 'previewGridpreviewBtn버튼Gird' 까지 전부 덧붙여지는 것을 확인할 수 있다.
Button을 클릭했을 때
Grid를 클릭했을 때
Tunneling Event는 최상위 root에서 시작하여 Event 발생 시점까지 도달하는 이벤트로 Bubbling Event와는 순서가 정반대이고 Event 이름에 Preview가 붙는 것이 특징인데, PreviewMouseDown이 이에 해당한다.
즉, Button을 클릭하면 트리 중 최상위인 Grid의 PreviewMouseDown 이벤트부터 동작하여 Button의 MouseDown 이벤트까지 도달하기 때문에 위의 화면과 같이 실행된 것이다.
덧붙여 Button의 MouseDown 이벤트는 마우스 우클릭을 했을 경우에만 이벤트를 수신한다. 그런데 PreviewMouseDown 이벤트는 마우스 좌클릭을 했을 때에도 이벤트를 수신한다.
- WPF는 기본적으로 Event명에 Preview가 붙지 않은 Event는 Bubbling Event이고 Preview가 붙은 Event명은 Tunneling Event로 구분할 수 있다.
- Direct Event는 이론 상으로는 Button을 클릭하면 Button의 Event만 발생다고 하는데 실제로는 Bubbling Event, Tunneling Event 처럼 동작하기 때문에 없는 셈 치는게 WPF 배우기에 쉬울 수 있다고 한다.(강사님 말씀)
컨트롤은 크게 Layout과 Layout 외의 컨트롤로 구분된다.
- Layout 컨트롤은 Gird, StackPanel, WrapPanel...등의 자식 요소의 위치, 배치 등에만 관심 있는 컨트롤을 말하고
- Layout 외의 컨트롤은 Button, TextBox, Label, Image, ListView...등의 컨트롤을 말한다.
Layout 컨트롤 중 가장 대표적인 것으로 Grid가 있다.
Gird 안에 Button, TextBox, Label, Calendar를 배치하고 Grid에 MouseDown 이벤트를 추가한다.
Grid의 MouseDown 이벤트로 MessageBox.Show("grid");를 동작하게 하는 코드를 작성한다.
private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("grid");
}
실행해보면 Label을 클릭했을 때 메세지박스로 grid가 출력되는 것으로 Grid의 MouseDown 이벤트가 동작하는 것을 알 수 있다.
Grid가 Label이나 Button 등의 컨트롤보다 상위 요소이기 때문이다.
그러나 Grid 영역을 클릭했을 경우에는 Grid의 MouseDown 이벤트를 수신하지 않는다.
Grid, StackPanel 등의 Layout 컨트롤은 자식 요소들에서 발생한 이벤트만을 수신한다는 특징이 있다.
참고로 Button의 경우 마우스 좌클릭을 했을 경우 Grid의 MouseDown 이벤트가 동작하지 않는다. (위와 마찬가지로 마우스 우클릭을 했을 때에만 동작한다.)
그 이유는 Layout이 아닌 컨트롤 중 몇 가지는 이미 내부적으로 기능이 구현되어있을 가능성이 높기 때문이다.
Button은 특히 이미 마우스 좌클릭 동작에 내부 기능이 있다.
확인은 마우스를 Button위로 올리거나 누르고 있는 상태를 보면 기본적으로 Button의 Background 색상이 하늘색이 되는 것으로 할 수 있다.
이렇듯 이미 내부 기능이 있어 작성한 이벤트 함수에서 수신을 안한다면 이벤트가 우회되는 함수를 찾는 것이 좋다.
이걸 생각하기 싫다 하면 주로 Bubbling Event와 쌍을 이루는 Tunneling Event로 처리하는 방법도 있다.
Label의 이벤트 함수를 보면 MouseDown과 PreviewMouseDown이 있다.
이 중 PreviewMouseDown의 이벤트를 작성하고 실행하면
private void Label_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("tunneling");
}
MessageBox에 tunneling이 출력된다. 앞서 작성했던 상위 요소인 Grid MouseDown 이벤트가 동작하지 않은 것이다.
이유는 Message.Show()나 .ShowDialog()와 같은 함수 사용 시 Focus가 강제되면서 Tunneling Event에서 Bubbling Event로 넘어가지 않는 특징 때문이다.
Tunneling Event 함수와 Bubbling Event 함수가 겹칠 경우 최상위 root에서 시작하는 Tunneling Event가 먼저 실행되고 또 Focus가 강제되는 코드나 e.Handled = true; 같은 코드가 없을 경우에만 다음 Bubbling Event 함수가 실행된다.
수업 완료 ~
7강, 8강은 필히 다시 들어야 할 것 같다.