C# 애플리케이션 개발에서는 인터페이스가 응답을 중지하지 않도록 작업자 스레드에서 UI 스레드를 분리하는 경우가 많습니다. 동시에 우리는 작업 스레드에서 UI 인터페이스의 컨트롤을 업데이트해야 합니다.
다음은 일반적으로 사용되는 몇 가지 방법을 소개합니다.
스레드 간의 작업은 유효하지 않습니다.
인터페이스에 버튼과 레이블이 있습니다.버튼을 클릭하면 스레드를 시작하여 레이블 값을 업데이트하십시오.
- private void button1_Click(개체 발신자, EventArgs e)
- {
- 스레드 thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel));
- thread1.Start("업데이트 Label");
- }
- 개인 무효 UpdateLabel(개체 str)
- {
- this.label1.Text = str.ToString();
- }
실행 후 프로그램은 ""label1"을 생성하지 않은 스레드에서 액세스하는 크로스 스레드 작업이 유효하지 않습니다."라는 오류를 보고합니다.
이는 .NET이 스레드 간 컨트롤 호출을 금지하기 때문입니다. 그렇지 않으면 누구나 컨트롤을 조작할 수 있으므로 결국 오류가 발생할 수 있습니다.
다음은 여러 스레드에서 컨트롤을 호출하는 몇 가지 방법을 소개합니다.
첫 번째 방법: 컴파일러가 크로스 스레드 액세스를 확인하지 못하게 합니다. 이것은 가장 간단한 방법으로 스레드 간의 충돌을 확인하지 않고 각 스레드가 엉망이 되도록 하는 것과 같습니다. 마지막으로, Label1 컨트롤의 값이 무엇인지 예측할 수 없음( 이 방법은 권장하지 않음 )
- 공개 Form1()
- {
- InitializeComponent();
- // 이 줄을 추가
- Control.CheckForIllegalCrossThreadCalls = 거짓;
- }
두 번째 방법: 위임 및 호출을 사용하여 다른 스레드에서 컨트롤을 호출하여 컨트롤의 호출 메서드를 호출한 다음 예를 들어 컨트롤을 제어할 수 있습니다.
- private void button2_Click(개체 발신자, EventArgs e)
- {
- 스레드 thread1 = new Thread(new ParameterizedThreadStart(UpdateLabel2));
- thread1.Start("업데이트 Label");
- }
- 개인 무효 UpdateLabel2(개체 str)
- {
- if (label2.InvokeRequired)
- {
- // 컨트롤의 InvokeRequired 속성 값이 true이면 컨트롤을 생성하는 스레드가 아닌 다른 스레드에서 액세스를 원한다는 의미입니다.
- Action<string> actionDelegate = (x) => { this.label2.Text = x.ToString(); };
- // 또는
- // Action<string> actionDelegate = delegate(string txt) { this.label2.Text = txt; };
- this.label2.Invoke(actionDelegate, str);
- }
- 또 다른
- {
- this.label2.Text = str.ToString();
- }
- }
세 번째 방법: 대리자와 BeginInvoke를 사용하여 다른 스레드에서 컨트롤을 제어합니다. 위의 this.label2.Invoke(actionDelegate, str);에서 Invoke를 BeginInvoke 메서드로 변경하면 됩니다.
Invoke 메서드와 BeginInvoke 메서드의 차이점은 다음과 같습니다. 해당
Invoke 메서드는 동기식이며, 작업자 스레드가 완료될 때까지 대기하고,
BeginInvoke 메서드는 비동기식이며, 다른 스레드를 시작하여 작업자 스레드를 완료합니다.
네 번째 방법: BackgroundWorker 구성 요소 사용(이 방법 사용 권장) BackgroundWorker는 프로그래머가 별도의 스레드에서 일부 작업을 수행할 수 있도록 하는 다중 스레드 작업을 위해 .NET 컨트롤에서 실행하는 데 사용됩니다. 다운로드 및 데이터베이스 트랜잭션과 같이 시간이 많이 걸리는 작업. 사용하기 쉬운
- private void button4_Click(개체 발신자, EventArgs e)
- {
- (BackgroundWorker bw = new BackgroundWorker()) 사용
- {
- bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
- bw.DoWork += new DoWorkEventHandler(bw_DoWork);
- bw.RunWorkerAsync("탱크");
- }
- }
- void bw_DoWork(개체 발신자, DoWorkEventArgs e)
- {
- // 이것은 다른 스레드에서 수행되는 백그라운드 스레드입니다.
- // 실제로 작업을 수행하는 작업자 스레드는 다음과 같습니다.
- // 여기에서 시간이 많이 걸리고 복잡한 작업을 수행할 수 있습니다.
- 스레드.슬립(5000);
- e.Result = e.Argument + "작업자 스레드 완료";
- }
- 무효 bw_RunWorkerCompleted(개체 발신자, RunWorkerCompletedEventArgs e)
- {
- // 이때 백그라운드 쓰레드가 완료되어 메인 쓰레드로 반환되었으므로 UI컨트롤을 바로 사용할 수 있다.
- this.label4.Text = e.Result.ToString();
- }