Thread를 이용하여 현재 시간을 나타내주는 프로그램.
일단, WPF 응용프로그램 프로젝트를 만든다.
그 후 XAML 코드에 간략하게 보일 TextBox를 하나 만들어 준다.
그 후 아래와 같이 코딩...
public partial class Window1 : Window { public delegate void TempDelegate(); public TempDelegate tempDelegate; Timer _timer = null; public Window1() { InitializeComponent(); InitTimer(); } private void InitTimer() { if (_timer != null) return; TimerCallback tcb = new TimerCallback(ThreadFunc); _timer = new Timer(tcb, null, 0, 1000); } public void ThreadFunc(Object stateInfo) { textBox1.Text = DateTime.Now.ToString(); } private void SetTextBox() { SetTextBox("-"); } private void SetTextBox(string strTemp) { textBox1.Text = DateTime.Now.ToString(); } }
빌드 후 실행 하면!!!!
위와 같은 에러 발생!!!
다름 아닌 Cross Thread Error...
Cross Thread Error 란..
xaml에서 만든 textbox UI를 생성한 Thread와 우리가 만든 Thread가 달라 textbox UI를 수정할 수 없는 상황에서 발생 하는 에러!!
즉, 내가 생각하기로는 WPF는 STA( Single Thread Application )이다.
WPF의 UI는 WPF의 메인 Thread에서 모두 생성한다.!! 그리하여 UI의 값들을 변경하고자 할때 따로 생성한 Thread에서는 수정할 수 없고 메인 Thread에서만 수정이 가능하다!
라고 생각하고 정의하고 있습니다.! ( 만약 다르다면... 댓글 남겨주세요..ㅠㅠ )
그리하여 상단의 ThreadFunc 에서 textBox에 접근하는 것은 Cross Thread Error 라는 것 !
이러한 문제를 막기 위해 내가 생성한 Thread에서 UI에 접근하여 수정 시 WPF의 메인 Thread에게 UI의 값을 수정 해달라고 요청을 해야 한다는 것..!! 그리하여 나타난 것이 Dispatch의 invoke, begininvoke..!!
사용 방법은 아래와 같다..
public partial class Window1 : Window { public delegate void TempDelegate(); public TempDelegate tempDelegate; Timer _timer = null; public Window1() { InitializeComponent(); InitTimer(); } private void InitTimer() { if (_timer != null) return; TimerCallback tcb = new TimerCallback(ThreadFunc); _timer = new Timer(tcb, null, 0, 1000); } public void ThreadFunc(Object stateInfo) { if (this.Dispatcher.Thread != Thread.CurrentThread) { tempDelegate += new TempDelegate(SetTextBox); Dispatcher.Invoke(DispatcherPriority.Normal, tempDelegate); } } private void SetTextBox() { textBox1.Text = DateTime.Now.ToString(); } }
위와 같이 작성하면 문제가 일어나지 않는다..!!
작성된 코드에서
if (this.Dispatcher.Thread != Thread.CurrentThread)
위 문은 this.Dispactcher.Thread와 Thread.CurrentThread가 같지 않다.
즉, 메인 Thread와 내가 생성한 Thread가 다를 시에는!!
아래의 구문을 사용한다라는 뜻!!
tempDelegate += new TempDelegate(SetTextBox); Dispatcher.Invoke(DispatcherPriority.Normal, tempDelegate);
Delegate를 생성하여 실행할 함수를 지정해주고 지정한 Delegate를 Invoke로 실행해주어
Cross Thread를 방지하는 것이다..
위 예제는 Invoke만 했는데 BeginInvoke로도 가능하다.. 예제는 다음 포스팅에서.......
2014/06/09 - [Skill/C#] - WPF의 Cross Thread BeginInvoke 방법