2008-10-15 8 views

Odpowiedz

10

Istnieje ogólna reguła, która mówi, że nie aktualizuje interfejsu użytkownika z żadnego wątku innego niż sam wątek interfejsu użytkownika. Korzystanie z funkcji programu BackgroundWorker jest dobrym pomysłem, ale użytkownik nie chce, a coś dzieje się w innym wątku, należy wykonać polecenie "Invoke" lub BeginInvoke, aby zmusić delegata do wykonania metody w wątku interfejsu użytkownika.

Edycja: Jon B wykonane to dobry punkt w komentarzach:

Należy pamiętać, że Invoke() jest synchroniczne i BeginInvoke() jest asynchroniczny. Jeśli użyjesz funkcji Invoke(), musisz uważać, aby nie spowodować impasu . Polecam BeginInvoke(), chyba że naprawdę potrzebujesz wywołanie być synchroniczne.

Niektóre prosty przykład kodu:

// Updates the textbox text. 
private void UpdateText(string text) 
{ 
    // Set the textbox text. 
    m_TextBox.Text = text; 
} 

public delegate void UpdateTextCallback(string text); 

// Then from your thread you can call this... 
m_TextBox.Invoke(new UpdateTextCallback(this.UpdateText), 
    new object[]{"Text generated on non-UI thread."}); 

Powyższy kod jest z FAQ o tym here i dłuższe bardziej zaangażować jeden here.

+0

Co dokładnie robi funkcja m_TextBox.Invoke? Czy zmusza delegata do wykonania w wątku UI? – Yttrium

+4

Dokładnie. Należy pamiętać, że funkcja Invoke() jest synchroniczna, a funkcja BeginInvoke() jest asynchroniczna. Jeśli używasz Invoke(), musisz uważać, aby nie spowodować zakleszczenia. Polecam BeginInvoke(), chyba że naprawdę potrzebujesz połączenia, aby być synchronicznym. –

+0

Dobra rozmowa, Jon B. Powinienem to wspomnieć. Będę edytować, aby odzwierciedlić punkt. –

5

Dlaczego nie chcesz tego zrobić za pomocą narzędzia BackgroundWorker? Ma fantastyczne wywołanie zwrotne o nazwie ProgressChanged, które pozwala wątkowi UI wiedzieć o aktualizacjach, idealne dla aktualizacji typu paska postępu i tym podobnych.

link to details

1

Istnieje dyskusja dotyczy tego here i jeden here.

Zasadniczo używasz Invoke, aby to osiągnąć.

Powodzenia!

1

Chciałbym również rozważyć InvokeRequired (tylko VS2008) podczas wywoływania Invoke. Są chwile, że nie będziesz aktualizować interfejsu użytkownika z osobnego wątku. Oszczędza narzut związany z tworzeniem delegata itp.

if (InvokeRequired) 
     { 
      //This.Invoke added to circumvent cross threading exceptions. 
      this.Invoke(new UpdateProgressBarHandler(UpdateProgressBar), new object[] { progressPercentage }); 
     } 
     else 
     { 
      UpdateProgressBar(progressPercentage); 
     }