Wątki, delegaty, eventy

0

Witam,

   Napisałem prostą aplikację na dodatkowym wątku, a w nim delegat z eventem
public delegate void MojDelegat();
        public event MojDelegat MojeZdarzenie;

oraz podpinam go pod formatkę

klasa.MojeZdarzenie += delegate
{
checkBox1.checked = false;
}

Dostaję error

Nieprawidłowa operacja między wątkami: do formantu 'checkBox1' uzyskiwany jest dostęp z wątku innego niż wątek, w którym został utworzony.

Czy istnieje jakiś prosty sposób(mam dużo formantów do zmiany przez zdarzenie) na uzyskanie dostępu do formantów bez Invokacji każdego formantu z osobna?

0

co to formanty? :) chyba mowisz o kontrolkach lub moze o formatkach, formach

nie ma innego wlasciwego sposobu, musisz uzyc InvokeRequired i jesli jest potrzebne Invoke (na kontrolce formie)
jesli na dane zdarzenie chcesz modyfikowac wiecej niz jedna kontrolke, funkcja, ktora wywolasz przez Invoke tez powinna to robic, wiec nie musisz dla kazdej z osobna wywolywac Invoke

a tak w ogole to wydaje mi sie ze masz jakies bledy w architekturze aplikacji, napisz cos wiecej to pokierujemy na wlasciwe tory

0
klasa.MojeZdarzenie += delegate
{
if (checkBox1.InvokeRequired)
                {
                    checkBox1.BeginInvoke((MethodInvoker)delegate
                    {
                        checkBox1.Checked = false;
                    });
                };
if (checkBox2.InvokeRequired)
                {
                    checkBox1.BeginInvoke((MethodInvoker)delegate
                    {
                        checkBox2.Checked = false;
                    });
                };
};

Moje zdarzenie z formy wygląda jak wyżej, jak widać dla każdej kontrolki oddzielnie wywołuję invokację. W drugiej klasie, w funkcji która jest uruchomiona jako wątek wywołuję "MojeZdarzenie();". Nie wiem jak mam to zrobić, żeby invokować tylko raz dla danego zdarzenia.

0

klasa.MojeZdarzenie += ()=>{ZrobCosTam();};

void ZrobCosTam()
{ // zakladam ze to jest w klasie formularza
if (this.InvokeRequired)
this.Invoke(new MojDelegat(ZrobCosTam));
else
{
checkbox1.checked = true;
checkbox2.checked = false;
textbox1.Text = "foo";
...
}
}

0

co to formanty?
Rozumiem, że to oficjalne tłumaczenie komunikatu o błędzie (tzn. taki dostał). Pretensje więc kierujesz do nieodpowiedniej osoby...

0

Azarien masz racje, czasem kreatywnosc tlumaczy mnie poraza. Tlumaczenie niektorych exceptionow w .net sa koszmarne.

0

A może tak?

this.Invoke(new EventHandler(delegate{ZrobCosTam();}}));


Poza tym niedawno był tu ciekawy wątek jak zrobić, żeby zdarzenie wykonywało się już w głównym wątku i nie trzeba było stosować Invoke (tak jak BackgroundWorker ma zrobione)
0

Azarien masz racje, czasem kreatywnosc tlumaczy mnie poraza. Tlumaczenie niektorych exceptionow w .net sa koszmarne.

Dział tłumaczeń Microsoftu często sili się na wymyślanie „poważnych”, ”oficjalnych” odpowiedników słów, dla których od dawna istnieją potoczne określenia. Nigdy nie ma „zresetuj”, zawsze jest „uruchom ponownie”. Czasem w ten sposób powstają potworki, których nikt w mowie nie używa.

1

Nigdy nie ma „zresetuj”, zawsze jest „uruchom ponownie”.

Przynajmniej dbają o czystość polskiej mowy ;)

0
othello napisał(a)

A może tak?
Poza tym niedawno był tu ciekawy wątek jak zrobić, żeby zdarzenie wykonywało się już w głównym wątku i nie trzeba było stosować Invoke (tak jak BackgroundWorker ma zrobione)

Jakbyś podał ramy czasowe kiedy ten ciekawy wątek mógł powstać byłbym wdzięczny.
Czy zalecacie używać BackgroundWorker'a zamiast zwykłego wątku?

0

Nie jestem ekspertem ale to co mówisz jest raczej tylko możliwe gdy mamy zadeklarowaną metodę w oknie głównym.

powiedzmy, że mamy klasę Point (tylko dla zobrazowania)

class Point {
public int x;
publix int y;
}

teraz mamy inną klasę w której jednym z elementów będzie Point

class Dzialania {

private Point Punkt = new Point()t;


public delegate void DelegatPunktu(Point _punkt);
public event DelegatPunktu PobierzPunkt;


public void Przypisz_Punkt()
{
this.Punkt.x = 10;
this.Punkt.y = 20;

if(PobierzPunkt != null) PobierzPunkt(this.Punkt); // sprawdzamy czy do eventu jest przypisana jakaś funkcja
}
}

Tutaj mamy kod główny programu :

{
...
Dzialania dzialanie = new Dzialania();


public Form1() //inicjalizacja formy
{
InitializeComponent();
dzialanie.PobierzPunkt += new dzialanie.DelegatPunktu(ShowPunkt);    
}


private void ShowPunkt(Point punkt)
{
label1.Text = punkt.X.ToString();
label2.Text = punkt.Y.ToString();
}
}

i teraz jeśli po naciśnieciu przycisku wywołamy

 dzialanie.PrzypiszPunkt() 

automatycznie wykona się funkcja ShowPunkt i do labeli będzie przypisana wartość

pisałem bez kompilatora, ale raczej błędów być nie powinno.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.