[C#] Invoke z wątku


(Marcin Obala) #1

Witam

Korzystam w aplikacji z wątków i timera i chcę zmieniać tekst w labelach, textboxach itd. Wszystko ok ale dla każdego textboxa, labela i innych mam różne funkcje.

zmienTextBox1(string txt);

zmienTextBox2(string txt);

zmienTextBox3(string txt);

cały kod wygląda tak:

public void zmien_label2(string txt)

{

	if(InvokeRequired)

	{

		this.Invoke(new Action(zmien_label2),new object[]{txt});

		return;

	}

	label2.Text=txt;

}

Czy nie da się zrobić tak że będę miał jedną funkcję i następnie jakoś przekazać kontrolkę przez parametr? Bo można zrobić obejście (chociaż nie wiem czy zadziała), dać zmienną Control, dać jedną funkcję, przed wywołaniem funkcji przypisywać do zmiennej Control jakiś label, textBoxt a następnie zmieniać w tej funkcji wartość tekstową tej kontrolki. Ale czy można to zrobić w ten sposób żeby przekazać przez parametr? Mi podkreśla linijkę z new Action jeśli dodam parametr.

Pozdrawiam.


(Frankfurterium) #2

Pewnie, że można. Tylko nie każdej kontrolce można ustawić .Text Ja bym dorzucił proste zabezpieczenie, żeby przypadkiem nie próbować wrzucić tekstu do np. ProgressBara.

public void SetText(Control control, String text)

        {

            if (control is Label || control is TextBox)

                control.Text = text;

        }
  • twoje wątki. I potem

    SetText(label2, "Ala");

    SetText(label3, "ma");

    SetText(textBox1, "kota.")


(Marcin Obala) #3

Tak tylko, że zapomniałeś o tym, że wywołanie jest z wątku i przy takiej budowie wyrzuci wyjątek.


(Somekindsoftware) #4

Na której niby nie można, skoro Text jest właściwością klasy Control, wszystkie klasy pochodne ją posiadają? :expressionless:


(Tomek Matz) #5
private void ChangeText(string text, Control c)

{

    if (c.InvokeRequired)

        Invoke(new Action(ChangeText), new object[] { text, c });

    else

        c.Text = text;

}

(Marcin Obala) #6

A widzisz, ja dopisywałem parametr i 'c' w nawiasie klamrowym obok text ale już nie pomyślałem o nawiasie ostrym żeby dopisać typ. Dzięki :wink:

:edit:

Wczoraj jak odpisywałem nie miałem już dostępu do projektu, sprawdzam to teraz i niestety nie działa. Wyświetla:

Using the generic type System.Action requires 1 type arguments.

Komunikat mówi sam za siebie. Chyba jednak będzie trzeba próbować obejściami ze zmienną globalną lub zrobić nową klasę z polami typu string i Control:

public class SetTextClass

{

	public string txt;

	public Control c;

	public SetTextClass(string t, Control con)

	{

		txt = t;

		c = con;

	}

}


private void ChangeText(SetTextClass variable)

{

    if (c.InvokeRequired)

        Invoke(new Action(ChangeText), new object[] {SetTextClass});

    else

        variable.c.Text = variable.txt;

}

ChangeText(new SetTextClass(newText,some_control));

Sprawdzałem i działa fajnie.


(Tomek Matz) #7

Z jakiej wersji .NET Framework korzystasz w projekcie? Jak widać w dokumentacji na stronie http://msdn.microsoft.com/en-us/library/dd402872.aspx delegat ten może przyjmować kilkanaście parametrów.


(Marcin Obala) #8

Chyba mam ustawiony .NET Framework 2 ustawione w celu największej kompatybilności.


(Tomek Matz) #9

To by wszystko wyjaśniało. Delegat Action dwa parametry może przyjmować dopiero od wersji .NET Framework 3.5. Obejście, które zastosowałeś jest jak najbardziej w porządku. Mogłeś także napisać własny delegat. Wówczas nie musiałbyś dodawać tej klasy, np.:

private delegate void ChangeTextDelegate(string text, Control c);


private void ChangeText(string text, Control c)

{

    if (c.InvokeRequired)

        Invoke(new ChangeTextDelegate(ChangeText), new object[] { text, c });

    else

        c.Text = text;

}