Szukaj…


Dostęp do kontrolek formularza z innych wątków

Jeśli chcesz zmienić atrybut formantu, taki jak pole tekstowe lub etykieta, z innego wątku niż wątek GUI, który utworzył formant, będziesz musiał go wywołać, w przeciwnym razie może zostać wyświetlony komunikat o błędzie:

„Niepoprawna operacja krzyżowa: kontrola„ nazwa_kontroli ”dostępna z wątku innego niż wątek, w którym została utworzona.”

Użycie tego przykładowego kodu w formularzu system.windows.forms spowoduje zgłoszenie wyjątku z tym komunikatem:

private void button4_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(updatetextbox);
    thread.Start();
}

private void updatetextbox()
{
    textBox1.Text = "updated"; // Throws exception
}

Zamiast tego, jeśli chcesz zmienić tekst pola tekstowego z wątku, który nie jest jego właścicielem, użyj Control.Invoke lub Control.BeginInvoke. Możesz także użyć Control.InvokeRequired, aby sprawdzić, czy wywołanie kontroli jest konieczne.

private void updatetextbox()
{
    if (textBox1.InvokeRequired)
        textBox1.BeginInvoke((Action)(() => textBox1.Text = "updated"));
    else
        textBox1.Text = "updated";
}

Jeśli musisz to robić często, możesz napisać rozszerzenie dla obiektów możliwych do wywołania, aby zmniejszyć ilość kodu niezbędną do wykonania tej kontroli:

public static class Extensions
{
    public static void BeginInvokeIfRequired(this ISynchronizeInvoke obj, Action action)
    {
        if (obj.InvokeRequired)
            obj.BeginInvoke(action, new object[0]);
        else
            action();
    }
}

A aktualizacja pola tekstowego z dowolnego wątku staje się nieco prostsza:

private void updatetextbox()
{
    textBox1.BeginInvokeIfRequired(() => textBox1.Text = "updated");
}

Należy pamiętać, że Control.BeginInvoke użyty w tym przykładzie jest asynchroniczny, co oznacza, że kod przychodzący po wywołaniu Control.BeginInvoke można uruchomić natychmiast po tym, czy przekazany delegat został jeszcze wykonany.

Jeśli musisz upewnić się, że textBox1 został zaktualizowany przed kontynuowaniem, użyj Control.Invoke, który zablokuje wątek wywołujący, dopóki twój delegat nie zostanie wykonany. Zwróć uwagę, że takie podejście może znacznie spowolnić kod, jeśli wykonasz wiele wywołań invoke, i zwróć uwagę, że zablokuje aplikację, jeśli wątek GUI czeka na zakończenie wątku wywołującego lub zwolnienie wstrzymanego zasobu.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow