028. UI Thread

2021. 11. 10. 19:26·사소한 아이의 소소한 스킬/C#
반응형

UI Thread에 대해서 알아보자....

 

(기본적으로 지금부터 하는말은 내가 이해한 수준으로 하는 말이므로 실질적으로는 다를수도 있다...)

 

WPF의 경우 UI에 데이터를 변경 할 시에는 UI Thread라는 Thread에서 모두 처리가 된다.

 

즉, 우리는 단순히 Label의 Content를 수정하지만, 내부적으로 파고 들어가면 UI Thread가 해당 작업을 해준다는 것..

 

그만큼 우리가 신경쓸게 많이 없단 이야기!! 그만큼 편하다!!!!

 

하지만 이러한 문제 때문에 문제가 발생되는 경우도 존재한다.

 

WPF의 기본 Thread(MainWindow의 작업)에서는 문제가 발생하지 않지만, 만약 다른 Thread를 만들어서 처리를 한다면.

 

UI Thread와 새로 만든 Thread간의 UI Component 접근에 문제가 생기는 부분..

 

이러한 부분을 WPF의 UI Thread 문제라고 한다

 

이러한 부분은 구글에서 검색만해도..

 

 

이렇게나 많이 나온다..

(내 글이 이제 검색하면 나왔으면 좋겠다............)

 

일단.. UI Thread의 문제나는 코드에 대해서 알아보자..

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<Window x:Class="TestProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"      
        xmlns:local="clr-namespace:TestProject"
        mc:Ignorable="d"
        Title="MainWindow" Height="500" Width="650">
    <Grid >
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
 
        <Grid Grid.Row="0">
            <Label x:Name="lb" Content="ABCDEF"/>
        </Grid>
 
        <Grid Grid.Row="1">
            <StackPanel Orientation="Horizontal">
                <Button Width="120" Content="CHANGE" Click="Button_Click"/>
                <Button Width="120" Content="THREAD_CHANGE" Click="Button_Click2"/>
            </StackPanel>
 
        </Grid>
    </Grid>
</Window>
 
Colored by Color Scripter
cs

 

간단하게 만들었다..

 

2개의 버튼을 생성하고 상단의 Label을 배치..

 

Code-Behind로는

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
 
 
namespace TestProject
{
    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>    
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
 
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            lb.Content = "CHANGE";
        }
        private void Button_Click2(object sender, RoutedEventArgs e)
        {
            Thread A_START = new Thread(lb_change);
            A_START.Start();
        }
 
        private void lb_change()
        {
            lb.Content = "THREAD_CHANGE";
        }
    }
}
Colored by Color Scripter
cs

 

2개의 버튼을 매칭시켜놨고, 1개의 버튼은 자체 STA Thread에서 Label을 변경

 

또 다른 1개는 새로운 Thread를 생성하여 Label을 변경.

 

이렇게 처리하였다.

 

기본적인 STA에서는 값이 변경이 잘 되지만... 새로운 Thread 생성 시 UI Thread 문제가 발생된다.

 

(아주 잘 작동하는 모습)

 

UI Thread 문제 발생!

 

그렇다면 이렇게 새로운 Thread 생성 시 문제가 발생시에 어떻게 처리하여야 하는가..?

 

방법은 새로운 Thread에서 UI를 수정하는것이 아닌 기존 STA Thread에서 UI를 수정하도록 해주는 것..

 

그 작업이 Dispacher이다.

 

아래와 같이 코드를 수정해보도록 하자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
 
namespace TestProject
{
    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>    
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
 
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            lb.Content = "CHANGE";
        }
        private void Button_Click2(object sender, RoutedEventArgs e)
        {
            Thread A_START = new Thread(lb_change);
            A_START.Start();
        }
 
        private void lb_change()
        {
            Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
            {
                lb.Content = "THREAD_CHANGE";
            }));
 
        }
    }
}
Colored by Color Scripter
cs

 

Thread 내부에서 Label을 변경해주는 부분을 Dispacher를 통해 처리를 하도록 하였다..

 

어떻게 처리를 한다면 문제 없이 Label의 데이터가 변경이 된다.

 

 

물론 이렇게 Dispacher를 사용해도 되고 아래와 같이 사용해도 된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
 
namespace TestProject
{
    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>    
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
 
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            lb.Content = "CHANGE";
        }
        private void Button_Click2(object sender, RoutedEventArgs e)
        {
            Thread A_START = new Thread(lb_change);
            A_START.Start();
        }
 
        private void lb_change()
        {
            //Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
            //{
            //    lb.Content = "THREAD_CHANGE";
            //}));
 
            if (lb.Dispatcher.CheckAccess())
            {
                lb.Content = "THREAD_CHANGE_2";
            }
            else
            {
                Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
                {
                    lb.Content = "THREAD_CHANGE_2";
                }));
            }
        }
    }
}
Colored by Color Scripter
cs

 

크게 다른부분은 없고  label의 Dispacher에 접근하여 해당 UI를 수정할 수 있는 Thread인지를 확인 한 후 수정할 수 있는 Thread의 경우 바로 수정, ㅇ니라면 UI Thread에서 처리. 하는 방식..

 

해당 사항이 한번 체크를 하고 하는 방식이므로 더 좋은 방안이라고 생각되기도 한다.

 

이상 끝!!

 

코드는 여기

TestProject.zip
0.09MB

 

반응형
'사소한 아이의 소소한 스킬/C#' 카테고리의 다른 글
  • 030. Visual Studio 오류
  • 029. Logical Operator (| , & 연산자)
  • 027. 압축설정/압축해제
  • 025.Thread/Task
JOOJI
JOOJI
그냥 혼자좋아하는 것들 남기는 블로그....
  • JOOJI
    사소한프로그래머의 소소한행복
    JOOJI
  • 전체
    오늘
    어제
    • 분류 전체보기 (951) N
      • 사소한 아이의 소소한 일상 (245)
      • 사소한 아이의 소소한 먹거리 (43)
      • 사소한 아이의 소소한 정보 (75) N
      • 사소한 아이의 소소한 감사 (4)
      • 사소한 아이의 소소한 운동 (53) N
      • 사소한 아이의 소소한 여행 (40)
        • 2013_전주 (1)
        • 2014_독일 (13)
        • 2014_군산 (1)
        • 2015_제주도 (3)
        • 2015_서울모토쇼 (3)
        • 2015_진해 (1)
        • 2015_전주 (1)
        • 2016_여수 (1)
        • 2020_강릉 (1)
        • 2022_제주도 (4)
      • 사소한 아이의 소소한 강짱 (22)
        • 하트투하트 (10)
        • MAPS (1)
        • 화려한 유혹 (2)
        • 한여름의 추억 (2)
      • 사소한 아이의 TV (50)
        • Drama (9)
        • 예능 (32)
        • 사소한 아이의 다현 (9)
      • 사소한 아이의 소소한 스킬 (130)
        • Scaleform (2)
        • C# (74)
        • QT (3)
        • 알고리즘 (4)
        • Python (21)
        • PyQT5 (9)
        • C_C++ (2)
      • 사소한 아이의 소소한 축구 (283)
        • Korea (25)
        • Germany (45)
        • Bayern Munich (64)
        • Soccer_ETC (75)
        • Euro 2016 (12)
        • 친선경기 (3)
      • 사소한 아이의 소소한 생활정보 (6)
  • 블로그 메뉴

    • 홈
    • 태그
    • 미디어로그
    • 위치로그
    • 방명록
    • 관리
  • 링크

    • 독일여행
    • 레바티스토리
    • 프라치노 공간
    • 남성패션꿀템 블로그
  • 공지사항

  • 인기 글

  • 태그

    c#
    독일
    회사밥
    러닝
    뮌헨
    WPF
    분데스리가
    문제
    python
    바이에른 뮌헨
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
JOOJI
028. UI Thread
상단으로

티스토리툴바