Sie haben recht, ist es nicht gut Kontrollen auf Threads zu übergeben. Winforms-Steuerelemente sind single-threaded, das Übergeben an mehrere Threads kann zu Race-Bedingungen führen oder die Benutzeroberfläche beschädigen. Stattdessen sollten Sie die Funktionen des Threads für die Benutzeroberfläche verfügbar machen und den Thread aufrufen, wenn die Benutzeroberfläche fertig und bereit ist. Wenn Hintergrundthreads Benutzeroberflächenänderungen auslösen sollen, legen Sie ein Hintergrundereignis offen und abonnieren Sie es über die Benutzeroberfläche. Der Thread kann Ereignisse auslösen, wann immer er möchte, und die Benutzeroberfläche kann auf sie reagieren, wenn dies möglich ist.
Das Erstellen dieser bidirektionalen Kommunikation zwischen Threads, die den UI-Thread nicht blockiert, ist eine Menge Arbeit. Hier eine gekürzte Beispiel eine Background-Klasse:
public class MyBackgroundThread : BackgroundWorker
{
public event EventHandler<ClassToPassToUI> IWantTheUIToDoSomething;
public MyStatus TheUIWantsToKnowThis { get { whatever... } }
public void TheUIWantsMeToDoSomething()
{
// Do something...
}
protected override void OnDoWork(DoWorkEventArgs e)
{
// This is called when the thread is started
while (!CancellationPending)
{
// The UI will set IWantTheUIToDoSomething when it is ready to do things.
if ((IWantTheUIToDoSomething != null) && IHaveUIData())
IWantTheUIToDoSomething(this, new ClassToPassToUI(uiData));
}
}
}
public partial class MyUIClass : Form
{
MyBackgroundThread backgroundThread;
delegate void ChangeUICallback(object sender, ClassToPassToUI uiData);
...
public MyUIClass
{
backgroundThread = new MyBackgroundThread();
// Do this when you're ready for requests from background threads:
backgroundThread.IWantTheUIToDoSomething += new EventHandler<ClassToPassToUI>(SomeoneWantsToChangeTheUI);
// This will run MyBackgroundThread.OnDoWork in a background thread:
backgroundThread.RunWorkerAsync();
}
private void UserClickedAButtonOrSomething(object sender, EventArgs e)
{
// Really this should be done in the background thread,
// it is here as an example of calling a background task from the UI.
if (backgroundThread.TheUIWantsToKnowThis == MyStatus.ThreadIsInAStateToHandleUserRequests)
backgroundThread.TheUIWantsMeToDoSomething();
// The UI can change the UI as well, this will not need marshalling.
SomeoneWantsToChangeTheUI(this, new ClassToPassToUI(localData));
}
void SomeoneWantsToChangeTheUI(object sender, ClassToPassToUI uiData)
{
if (InvokeRequired)
{
// A background thread wants to change the UI.
if (iAmInAStateWhereTheUICanBeChanged)
{
var callback = new ChangeUICallback(SomeoneWantsToChangeTheUI);
Invoke(callback, new object[] { sender, uiData });
}
}
else
{
// This is on the UI thread, either because it was called from the UI or was marshalled.
ChangeTheUI(uiData)
}
}
}
Bitte markieren eine Antwort als akzeptiert, wenn man Ihr Problem löst. – SandRock