WPF의 Cross Thread 문제
반응형

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 방법



반응형