WPF - UI 업데이트를 바로 반영하고 싶다면? (2)
우선 지난번 이야기를 아직 안 읽어보신 분들은 이 글의 이해를 위해 꼭 읽어보시기 바랍니다.
WPF - UI 업데이트를 바로 반영하고 싶다면?
; https://www.sysnet.pe.kr/2/0/747
아울러, 다음의 토픽도 읽어보시면 좋겠지요. ^^
WPF와 WinForm의 Shown 이벤트 시점
; https://www.sysnet.pe.kr/2/0/753
그런데, 이런 방법 외에 "마이크로소프트 직원"만이 ^^; 알 수 있는 듯한 방법이 하나 더 있습니다.^^
How can I expand items in a TreeView? - Part III
; http://bea.stollnitz.com/blog/?p=59
원래는 TreeView에 대해서 궁금한 것이 있어서 찾아보다가 우연히 보게 된 내용인데요. 아래와 같이 특정 DispatcherPriority까지의 실행이 모두 완료된 다음에 실행을 진행할 수 있게 하는 방법이 있습니다. (참고로 "
Bea stollnitz" 블로그 내용이 꽤나 읽을 거리가 많습니다.)
internal static void WaitForPriority(DispatcherPriority priority)
{
DispatcherFrame frame = new DispatcherFrame();
DispatcherOperation dispatcherOperation =
Dispatcher.CurrentDispatcher.BeginInvoke(priority,
new DispatcherOperationCallback(ExitFrameOperation), frame);
Dispatcher.PushFrame(frame);
if (dispatcherOperation.Status != DispatcherOperationStatus.Completed)
{
dispatcherOperation.Abort();
}
}
private static object ExitFrameOperation(object obj)
{
((DispatcherFrame)obj).Continue = false;
return null;
}
눈에 익지 않은 코드라서 어려워 보이지만 전체적인 동작 방식은 단순합니다. Dispatcher.CurrentDispatcher.BeginInvoke에 전달된 ExitFrameOperation 콜백 메서드는 (해당 Dispatcher를 소유한) 스레드의 WorkItem 처리 레벨이 전달된 "priority" 인자로 되었을 때 호출되게 됩니다. 만약 그때 Continue = false를 주면 DispatcherFrame을 벗어나고, 그렇지 않으면 지속적으로 스레드는 해당 DispatcherFrame에 머물러 있게 됩니다. (좀 더 자세한 이야기는 다음 기회에!)
결국, 사용법도 동일합니다. 예를 들어 아래와 같은 코드가 있을 때,
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Button Click="button1_Click">Button</Button>
<Label Grid.Row="1" x:Name="lblOutput" ></Label>
</Grid>
private void button1_Click(object sender, RoutedEventArgs e)
{
this.lblOutput.Content = Guid.NewGuid().ToString();
Thread.Sleep(5000);
}
보통, 이렇게 실행시키면 5초 동안 Label 컨트롤에는 아무 내용도 출력되지 않은 체로 화면이 먹통이 되어버립니다. 그런데, 다음과 같이 WaitForPriority를 추가하면,
private void button1_Click(object sender, RoutedEventArgs e)
{
this.lblOutput.Content = Guid.NewGuid().ToString();
WaitForPriority(DispatcherPriority.Background);
Thread.Sleep(5000);
}
예상할 수 있는 것처럼 화면에는 새로운 Guid 값이 출력되고 난 후에 Thread.Sleep으로 진입하게 됩니다.
지난번과 비교해서 다소 어려운 면이 있지만 재미있게도 이 예제를 통해서 Dispatcher에 대한 이해가 깊어지니 나름 의미가 있습니다. ^^
*
첨부된 파일은 테스트 예제입니다.
[이 토픽에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]