프로그래밍을 하다보면 Thread로 처리해야 하는 일들이 생기게 된다..

그런데 실버라이트에서는 객체를 컨트롤 할때 주스레드(UI thread)에서
처리 하지 않게되면 Cross Thread라는 문제를 발생시키다;
예제를 보면 쉽게 이해가 갈것이다!

구현하고자하는 프로그램!

간단히 실버라이트 page에 버튼하나와 TextBlock을 배치하여 버튼클릭시 TextBlock에
지정한 문자열을 표시하도록 했다!
-- page.xaml --

<UserControl x:Class="UIThread.Page"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
     <Button Height="85" HorizontalAlignment="Right" Margin="0,0,47,56" VerticalAlignment="Bottom" Width="142" Content="Make Thread" x:Name="btnThread"/>
     <TextBlock Height="82" Margin="22,22,32,0" VerticalAlignment="Top" Text="TextBlock" TextWrapping="Wrap" x:Name="txtTextBlock"/>
    </Grid>
</UserControl>



-- UI 화면 --



-- page.xaml.cs --

using System.Windows;
using System.Windows.Controls;
//Thread를 쓰기위한 using
using System.Threading;
namespace UIThread
{
    public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
            btnThread.Click += new RoutedEventHandler(btnThread_Click);
        }

        void btnThread_Click(object sender, RoutedEventArgs e)
        {
            //Thread 생성
            Thread thread = new Thread(Doit);
            thread.Start("스레드 작업 잘될까?");
        }

        //Cross Thread 발생 Method
        void CrossThread(object state)
        {
            string txt = (string)state;
            txtTextBlock.Text = txt;
        }

        //Cross Thread 해결한 Method
        void Doit(object state)
        {
            string txt = (string)state;
            //Dispatcher 사용
            Dispatcher.BeginInvoke(
                delegate()
                {
                    txtTextBlock.Text = txt;
                }
                );           
        }
    }
}
비하인드 코드에서 보는 바와 같이 버튼을 클릭하게 되면 Thread를 하나 생성하고

일반적으로 생각하기 쉬운 방법인 CrossThread 메소드를 호출해 보았다!

-- 오류화면 --

결과는 TextBlock이라는 문자열에 전혀 변화가 없고 왼쪽 하단에 오류만 덩그러니 일어난다!
오류 정보를 보니 잘못된 크로스 스레드 액세스란다;
txtTextBlock.Text = txt; 구문때문에 ""스레드 작업 잘될까?""라는 구문이 출력해야 맞을텐데;;

이것은 바로 실버라이트 UI의 스레드 모델때문이다!
실버라이트 컨트롤의 제어는 해당하는 주스레드에서 행해져야 하지만;
우리가 강제로 쓰레드를 생성하여 컨트롤을 변경하려 했기 떄문이다;

그렇다면 해결방법은? C# 의 Delegate처럼 주스레드에 변경을 부탁하면 된다!

부탁하는 방법은 UserControl 클래스가 가지고있는  Dispatcher을 사용하면 된다!
Dispatcher의 멤버로는 Dispatcher.Invoke()와 Dispatcher.BeginInvoke()가 있다;
잘알다싶이 Invoke는 동기식 BefinInvoke는 비동기 방식이다!!!

그럼 이번엔  Dispatcher를 사용한 Doit 메소드를 호출하여 보자!!

-- 실행 화면 --

위와같이 아무런 오류없이 잘 되는것을 확인할수 있다!!
Posted by 맨날맑음

댓글을 달아 주세요

  1. 을지랑 2009.05.13 13:09  댓글주소  수정/삭제  댓글쓰기

    오오 좋은 정보 얻어가요~

  2. 와와 2010.02.05 16:31  댓글주소  수정/삭제  댓글쓰기

    정말 좋은 정보입니다.
    이것땜에 고생많이 했는데~~~
    감사합니다^^