2009-09-14 5 views
10

은이 같은 함수의 Form_Load 함수스레드

public void ShowAllFly() 
{ 
     cbFly.Items.Clear(); 
     cbFly.Items.Add("Uçuş Seçiniz..."); 

     dsFlyTableAdapters.tblFlyTableAdapter _t=new KTHY.dsFlyTableAdapters.tblFlyTableAdapter(); 
     dsFly _mds = new dsFly(); 
     _mds.EnforceConstraints = false; 
     dsFly.tblFlyDataTable _m = _mds.tblFly; 
     _t.Fill(_m); 
     foreach (DataRow _row in _m.Rows) 
     { 
      cbFly.Items.Add(_row["FlyID"].ToString()+"-"+_row["FlyName"].ToString() + "-" + _row["FlyDirection"].ToString() + "-" + _row["FlyDateTime"].ToString()); 
     } 
     _Thread.Abort(); 
     timer1.Enabled = false; 
     WaitPanel.Visible = false; 
} 

이 Control.Invoke;

{ 
    _Thread = new System.Threading.Thread(new System.Threading.ThreadStart(ShowAllFly)); 
    _Thread.Start(); 
    _Thread.Priority = System.Threading.ThreadPriority.Normal; 
} 

하지만 실행하면;

cbFly.Items.Clear(); ---- HERE Gives ERROR LIKE Control.Invoke must be used to interact with controls created on a separate thread. 

문제가 무엇입니까 ShowAllFly 기능에

? 또 다른 (UI) 스레드에서 컨트롤에

답변

48

:

  • 돈 ' t 컨트롤의 "핸들"을 생성 한 스레드가 아닌 다른 스레드 (일반적으로 단 하나의 UI 스레드 만 있음)의 모든 컨트롤 속성 또는 메서드 (괜찮은 것으로 명시된 것들을 제외하고)를 터치하십시오.
  • 당신을 "마샬"전화를 필요
  • 시간의 상당한 기간 동안 UI 스레드를 차단하지 마십시오, 또는 당신은 다른 스레드에서 UI와 상호 작용하기 위해

응답하지 않는 응용 프로그램을 만들 수 있습니다 UI 스레드에 대리자를 사용하고 Control.Invoke/BeginInvoke을 호출하면됩니다. 일 수 있습니다. InvokeRequired 속성을 사용하여 Invoke에 전화해야하는지 여부를 테스트 할 수 있지만, 요즘에는 개인적으로 어쨌든 개인적으로 그렇게하는 경향이 있습니다. 필요하지 않을 때 호출 할 때 많은 불이익은 없습니다.

C# 3의 람다 식 (또는 C# 2의 익명 메서드)을 사용하면 훨씬 더 즐겁습니다.

cbFly.Invoke((MethodInvoker)(() => cbFly.Items.Clear())); 

모든 브래킷이 방법으로 비트를 얻을, 그래서 당신은 당신이 C# 3를 사용하는 경우, 다음과 같은 확장 방법을 추가 할 수 있습니다 :

예를 들어, 당신은 사용할 수

public static void Invoke(this Control control, MethodInvoker action) 
{ 
    control.Invoke(action); 
} 

그럼 당신은 할 수 : 좋은 거래 간단

cbFly.Invoke(() => cbFly.Items.Clear()); 

합니다. 대개 대리자 내에서 액세스해야하는 변수를 캡처하여 MethodInvoker을 사용할 수 있습니다.

자세한 내용은 my threading tutorial 또는 Joe Albahari's을 참조하십시오.

2 차적인 문제로, 나는 당신이 Thread.Abort을 사용하고있는 것을 본다. 실제로 그 후에 다른 호출이 있음에도 불구하고, 당신 자신의 스레드에있다. 왜? 임의의 스레드를 중단하는 것 다른은 자신의 것보다 "응급 전용"유형의 호출 (일반적으로 어쨌든 앱을 언로드해야 함)이며 아직 수행해야 할 작업이있을 때 현재 스레드를 중단 할 이유가 없습니다. 나중에...

6

상호 작용과 같이 호출 할 필요가 : 스레딩의 두 가지 황금 규칙이 윈도우 폼에 있습니다

public delegate void ProcessResultDelegate(string result); 
void ProcessResult(string result) 
{ 
    if (textBox1.InvokeRequired) 
    { 
     var d = new ProcessResultDelegate(ProcessResult); 
     d.Invoke(result); 
    } 
    else 
    { 
     textBox1.Text = result; 
    } 
} 
+3

좋은 솔루션; 나는 자신의 롤링 (유지)보다는 프레임 워크에서'Action '을 사용하는 것을 권할 것이다. –

+0

네 .. 이걸하는 것이 표준 방법입니다. 이것이 필요한 이유는 textBox1.Text가 텍스트 상자가 생성 된 스레드에서만 변경 될 수 있기 때문입니다. 호출은 해당 스레드로 돌아가는 데 사용되는 프로세스입니다. –

+0

@Fredrik : 당신 말이 맞아,하지만 더 오래되어 있기 때문에이 예는 많은 부분에서 더 자주 볼 수 있습니다. 어느 방법이든 작동합니다. –

3

나는 항상이 특정 문제에 도움이되는 this article을 발견했습니다. 당신의 예에서

, 당신은 컨트롤을 생성하지 않는 스레드에서 다양한 컨트롤을 수정하려고하고 있습니다. 귀하의 예를 주어진이 문제를 해결하기 위해, 대신합니다 (ShowAllFly() 메소드는 양식의 방법이라고 가정)이 작업을 수행 :

public void ShowAllFly() 
{ 
    Invoke((MethodsInvoker) delegate { 
     cbFly.Items.Clear(); 
     cbFly.Items.Add("Uçuş Seçiniz..."); 
     dsFlyTableAdapters.tblFlyTableAdapter _t = 
      new KTHY.dsFlyTableAdapters.tblFlyTableAdapter(); 
     dsFly _mds = new dsFly(); 
     _mds.EnforceConstraints = false; 
     dsFly.tblFlyDataTable _m = _mds.tblFly; 
     _t.Fill(_m); 
     foreach (DataRow _row in _m.Rows) 
     { 
      cbFly.Items.Add(_row["FlyID"].ToString() + "-" + 
          _row["FlyName"].ToString() + "-" + 
          _row["FlyDirection"].ToString() + "-" + 
          _row["FlyDateTime"].ToString()); 
     } 
     //_Thread.Abort(); // WHY ARE YOU TRYING TO DO THIS? 
     timer1.Enabled = false; 
     WaitPanel.Visible = false; 
    }); 
} 

그냥 @ 존 소총으로 만든 점을 강조하기 위해, 나는 주석했습니다 thread를 종료하기위한 호출 스레드는 자체적으로 끝날 것입니다. 이런 방식으로 중단 할 이유가 없습니다.

+1

당신은 최고의 매트입니다. 고맙습니다. 그것은 아주 잘 작동합니다. – atromgame

+0

그는 최고이기 때문에, 나는 그에게 upvote를 주었다. 나는 그 전에 아무도 가지고 있지 않았다. (힌트, 힌트). –

0

이해야 할 당신은 단지 다음 등을 만들 동시에 둘 이상의 프로세스를 이동하려면 호출 ...하지만 난 당신이 이런 식으로 에러하지 말은 여전히 ​​메인 스레드를 기다릴 필요가 호출하지만 exacly 평행하게 작동하지 않는이 하나 개의 스레드

Thread thread = new Thread(new delegate_method(method));//you must create delegate before 
thread.start(); 
Thread thread2 = new Thread(new delegate_method(method2));//you must create delegate before 
thread.start(); 

핸들이 과정을 동시에

void method() 
{ 
//do something here -- working background Remember can not control any UI control from here 
finish_thread() 
} 

void method2() 
{ 
//do something here -- working background Remember can not control any UI control from here 
finish_thread() 
} 

void finish_thread() 
{ 
if(invoke.Required) 
{ 
//Here you have to call delegate method here with UI 
BeginInvoke(new delegate_method(finish_thread)); 
} 
else 
{ 
//Now you can control UI thread from here and also you finished background work 
//Do something working with UI thread 
textBox.Text = ""; 
} 
} 
관련 문제