Zrobiłem kilka badań i nie mogę naprawdę znaleźć preferowany sposób aktualizowania formantów formularza z wątku roboczego w języku C#. Wiem o komponencie BackgroundWorker, ale jaki jest najlepszy sposób, aby to zrobić bez użycia składnika BackgroundWorker?Jaki jest najlepszy sposób aktualizacji formantów formularza z wątku roboczego?
Odpowiedz
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.
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.
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);
}
Co dokładnie robi funkcja m_TextBox.Invoke? Czy zmusza delegata do wykonania w wątku UI? – Yttrium
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. –
Dobra rozmowa, Jon B. Powinienem to wspomnieć. Będę edytować, aby odzwierciedlić punkt. –