내용 보기
작성자
관리자 (IP : 172.17.0.1)
날짜
2020-07-10 01:51
제목
[WPF] WPF - UI 업데이트를 바로 반영하고 싶다면?
|
기존 WinForm과 WPF의 UI 쓰레드 동작 방식이 달라졌습니다. WinForm에서는 기존 Win32 의 Window Proc구조를 단순히 확장한 것이었던 반면, WPF에서는 UI 쓰레드에 대해 WorkItem 방식으로 큐를 대기시켜서 처리하는 Dispatcher가 착 달라붙었습니다. WPF - Threading Model ; http://msdn.microsoft.com/ko-kr/library/ms741870(VS.85).aspx
using System;
using System.Windows.Forms;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.button1.Enabled = false;
Thread.Sleep(5000);
this.button1.Enabled = true;
}
}
}
private void button1_Click(object sender, RoutedEventArgs e)
{
this.button1.IsEnabled = false;
Thread.Sleep(5000);
this.button1.IsEnabled = true;
}
아래와 같이 특정 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 으로 진입하게 됩니다. |
출처1
http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&detail=1&wid=747
출처2
http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&detail=1&wid=753 / http://www.sysnet.pe.kr/Default.aspx?mode=2&sub=0&detail=1&wid=785
