[WPF] 'Dispatcher.Invoke'와 'Dispatcher.BeginInvoke'
WPF에서 다른 쓰레드에서 UI를 사용하려면 인보크를 사용해야 합니다.
(윈폼에서 비슷하긴 합니다.)
참고 : [WPF] 다른 스레드에서 UI쓰레드 접근하기 - Dispatcher.Invoke
1. 인보크(Invoke)와 비긴인보크(BeginInvoke)
디스페쳐(Dispatcher)에 있는 인보크는 두 종류가 있습니다.
'Invoke'는 지연이 없는 인보크고
'BeginInvoke'는 지연이 있는 인보크입니다.
2. 두 종류의 차이
정확하게 말해서는 Invoke는 동기적 동작을 하고
BeginInvoke는 비동기적 동작을 합니다.
(참고 : MSDocs - Dispatcher.Invoke 메서드, Dispatcher.BeginInvoke 메서드)
쓰래드라고해도 비동기 동작은 자신을 호출한 쓰레드가 끝나야 호출되기 때문에 UI 쓰레드에서 호출한 비동기 함수는 자연스럽게 UI 쓰레드가 한번 끝나야 동작합니다.
이것은 쓰레드의 특성 때문인데
쓰레드는 계속 트랙을 도는 사람이라고 생각하면
이 사람이 한반퀴 돌 때 쓰레드 하나의 일이 끝납니다.
이 사람은 스택에 쌓여있는 일만 하는데 비동기 동작은 이 스택의 끝에 쌓이니 한 바퀴가 끝나야 비동기로 등록된 일을 하게 되는 것입니다.
쉽게 이야기하라고 이렇게 설명한 거지 깊게 들어가면 설명할 게 넘쳐나니 바로 예제로 넘어가 보겠습니다. ㅎㅎㅎㅎ
3. 테스트를 해보자
WPF에서 클릭하면 전체가 선택되는 "TextBox"를 만들어 봅시다.
이 "TextBox"의 "GotFocus" 이벤트에 다음과 같은 코드를 넣어 봅시다.
별생각 없이 인보크(Invoke)를 사용하는 것과....
1
2
3
4
5
|
Dispatcher.Invoke(DispatcherPriority.Normal
, new Action(delegate
{
this.txtMoney.SelectAll();
}));
|
cs |
비긴 인보크(Begin Invoke)를 사용하는 것을 만들고
1
2
3
4
5
|
Dispatcher.BeginInvoke(DispatcherPriority.Normal
, new Action(delegate
{
this.txtMoney.SelectAll();
}));
|
cs |
테스트를 하면.....
그냥 인보크는 'textBox.SelectAll();'가 동작을 안 하는 것처럼 보이고
비긴 인보크는 'textBox.SelectAll();'가 동작하는 것처럼 보입니다.
이것은 포커스를 얻기 위한 클릭 이벤트가 일어나는 도중에 'textBox.SelectAll();'이 호출되느냐
이벤트가 끝나고 호출 되냐의 차이를 만들어 냅니다.
마무리
참고 : 샘플 프로젝트 - github - dang-gun WpfInvokeTest
이런 이벤트의 타이밍 문제 때문에 생각과 다른 결과가 일어나기도 합니다.
하지만 이런 건 그때그때 부딪쳐봐야 아는 것이죠 ㅎㅎㅎㅎ