내용 보기
작성자
관리자 (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