2011-08-28 12 views
7

Mam klasę serwera, która zasadniczo czeka na połączenia od klienta. Wewnątrz tej klasy tworzę obiekt NetworkStream, aby móc odbierać bajty od klienta. Ponieważ metoda NetworkStream.Read() nie jest asynchroniczna (co oznacza, że ​​będzie czekała aż odczyta bajty od klienta, aby kontynuować wykonywanie kodu podobnego do metody skrzynki komunikatów), muszę przeczytać bajty w osobnym wątku, aby użytkownik korzystający z programu może nadal wchodzić w interakcję z programem, jeśli program czeka na odczyt danych.Obiekt dostępu z innego wątku

mimo to wiele rzeczy jest własnością tego wątku. Jednym z przykładów jest to, że mam listę o nazwie log w tej klasie. Używam tej listy, aby poznać status serwera. Może to jest słuchanie połączenia lub może jego status jest "podłączony" lub "odłączony".

Więc jeśli mam coś takiego:

Server myServer = new Server("192.168.0.120","1300"...\\ I pass the appropite parameters in order to instantiate it 

//... 
.. then I am able to latter look at the log as 
string foo = myServer.Log[0] for example. 

bo chcę wiedzieć, kiedy dziennik jest aktualizowany, na klasie serwera Stworzyłem zdarzenie jako:

public delegate void onUpdateHandler(string newStatus); 
    public event onUpdateHandler onUpdate = delegate { }; 

Potem przeciwpożarowej wydarzenia na klasie serwera jako:

onUpdate("waitingForConnection"); 

i otrzymują te zdarzenia za pomocą metody:

enter image description here

ale gdy próbuję coś zrobić z NEWSTATUS otrzymuję błąd stwierdzając:

System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it. 

więc jak mogę przekazać obiekt ze zdarzeniem?


Edit

więc również zauważyć, że jeśli to zrobię:

enter image description here

ja również się błąd!

ale kiedy robię to samo wzywającą że z guzika jak:

// SERVER IS RUNNING BEFORE CALLING THIS METHOD 
    private void button3_Click(object sender, RoutedEventArgs e) 
    { 

     listView1.Items.Add("my own string"); 

    } 

nie pojawia się błąd!

Dlaczego jest to, że dostaję błąd z wydarzeniem i nie dostaję błędu podczas wywoływania go za pomocą zwykłego przycisku.

Odpowiedz

12

Problem polega na tym, że wątek próbuje uzyskać dostęp do ListView, który jest DependencyObject która posiada gwint powinowactwo, użyj Dispatcher wykonać metodami jak to na UI-wątku, np:

Application.Current.Dispatcher.Invoke((Action)(() => 
{ 
    listView1.Items.Add(newStatus); 
})); 

zobaczyć Również threading model reference, aby uzyskać dodatkowe informacje.

+0

kiedy miejsce to wewnątrz w mojej metodzie pojawia się komunikat o błędzie: Nie można przekonwertować wyrażenia lambda na typ "System.Delegate", ponieważ nie jest to delegat typu –

+0

@TonoNam: Oh tak, musisz go rzucić lub utworzyć akcję jawnie. –

+0

@Tono, lambda musi zostać przeniesiona do jakiegoś typu delegata, zobacz moją edycję. – svick

1

Problem nie polega na tym, że próbujesz coś zrobić z wartością wysłaną do metody, problem polega na tym, co próbujesz z nią zrobić.

Obsługa zdarzeń nadal działa w wątku w tle, a stamtąd nie można używać żadnych elementów sterujących interfejsu użytkownika, ponieważ należą one do głównego wątku.

Zazwyczaj sposobem postępowania, który jest użycie metody CheckAccess aby sprawdzić, czy trzeba przełączyć bieżniki, a metoda Invoke oddać się pracy do głównego wątku:

void server_onUpdate(string newStatus) { 
    if (!listView1.Dispatcher.CheckAccess()) { 
    listView1.Dispatcher.Invoke(server_onUpdate, newStatus) 
    } else { 
    listView1.Items.Add(newStatus); 
    } 
} 
+0

Według tagów to nie jest WinForms ... –

+0

@ H.B .: Już to poprawiłem. – Guffa

+0

@ Guffa ładne wyjaśnienie dzięki –

Powiązane problemy