Zdravíčko, mám zákys. Snažím se napsat TCP komunikátor klient-server-klient. V úplném začátku (jeden thread jeden stream a prevod z konzolovky do Formu) jsem narazil na problém nastávající:
V klientské aplikaci mám:
Třídu Form, tam zkrátka je jakýsi richTextBox_myMessage kam klient píše, button kterým to klient odpálí na server a richTextBox_conversation, kde se vytváří log z komunikace (příchozí a odchozí dokupy).
Dál třídu Client, v té hned ze začátku písknu na server, ten vytvoří NetworkStream. Pak je tam metoda Sent(string message), kterou zavolá button a do parametru jí šlehne richTextBox_myMessage.Text. No a blížíme s k problému... ten jest v metodě Listen().
Metoda Listen() je po vytvoření streamu volána samostatným threadem. Její úkol je prostý - v nekonečném cyklu poslouchá stream a v případě, že přijde zpráva od serveru, tak ji vezme a dekóduje. Výsledkem je string.
Můj problém je v tom, že nejsem schopný zařídit, aby se tato nečekaná událost (zpráva, která přijde ze serveru) projevila ve Formu (uložila do richTextBox_conversation). Ze třídy Client si nemůžu dovolit udělat něco jako Form.richTextBox_conversation.Text += string a cyklicky ve Form kontrolovat, jestli něco nepřišlo je stupidní. Při pokusu o vytvoření delegáta jsem zamrzl na tom bodě, že nevím, jak event projevit v jiné třídě, než kde je delegát deklarován. Takže se ptám na možná (i alternativní) řešení, pravděpodobně jak mám udělat event, který "protáhnu" skrze dvě třídy nespojené dědičností.
#1nirman
Můžeš si přece do nějaké "globální" třídy do static proměnné uložit odkaz na ten form a přes ten pak přistupovat k jeho prvkům, akorát budeš muset před tím nastavit CheckForIllegalCrossThreadCalls na false abys mohl k UI přistupovat napříč thready.
A nebo pokud je to v C++ tam pomocí SendMessage posklat WM_SETTEXT na handle toto richeditu.
Radek Chalupa
- vývoj software na zakázku
- školení programování (C/C++, WinAPI, ATL, COM, ActiveX, C#, NET Framework, MFC) http://www.radekchalupa.cz
Jde o C#. A k tomu odkazu na form - to nepobiram :D Do objektu ve Form ja nevidim at delam co delam, ale aji jak se snazim, me to prijde jako prasarna to takto resit, proto jsem se uchylil k tem eventum, coz se mi nepodarilo no.
já ted nevim jestli problém chápu správně... takže ty vlastně chceš... jakmile klient pošle zprávu na server, tak tuto zprávý poslat do formu do boxu?
Pokud jo, tak si vytvoříš normální událost s parametrem string, kde bude zpráva a akorát ji ve formu dáš tělo
tvar události můžeš mít třeba jako
// udalost na serveru
public event Action<string> ReadMessage;
// dokodovana zprava se posle do udalosti
if (ReadMessage != null)
ReadMessage(zprava);
// na strane Form jen vytvoris vlastni funkci
private void ReadMessage(string msg) { /* ... */ }
// a v konstruktoru Formu presmerujes udalost
server.ReadMessage += ReadMessage;
#5ingiraxo
Chapes to sice naopak (server odesle zpravu, klient ji prijme a ma ji vypsat do formulare), ale v tomto pripade je to jedno, napsal jsi mi uz z toho jak to vidim to, po cem se pidim. Jadro problemu je asi to, ze neumim poradne zachazet s eventy. Zkusim to, jen nevim, jestli se to bude chovat dynamicky, kdyz to server.ReadMessage += ReadMessage; je v konstruktoru formu a po vytvoreni (dle meho chabeho usudku) uz se to vicekrat nestane. Kdezto zpravy muzou chodit porad. Nic, prubnu a uvidim
#6nirman
ReadMessage bude událost jak napsal Ingiraxo, prostě si jí deklaruješ jako public a zvenčí se na ní budeš registrovat přes toto:
server.ReadMessage += ReadMessage
Kde ReadMessage bude metoda odpovídající předpisu události.
Pak ale ty sám někde v kódu, když ti přijde zpráva, tak budeš vyvolávat událost ReadMessage (ten event). Pokud nikdo nebude registrován, tak se nic neděje, pokud ale zaregistruješ více metod, tak budou všechny notifikovány o čtení zprávy.
Výhoda je v tom, že budeš mít server zapouzdřen, zprávy budeš odesílat třeba pomocí metody SendMessage a pokud nebudeš potřebovat čtení, tak se jednoduše registrovat nemusíš.
Dělal jsem něco obdobného, tak se klidně inspiruj:
Tak dobré, prakticky jsem se tu díky vám naučil v praxi použít eventy.. Teď mám problém toho, že když to mám zaobalené do dvou vláken (Thread ve třídě A, hlídající příchozí zprávu chce tuto zprávu odeslat do Form, což je samostatné vlákno). No a vlákna jsem používal dosavadně jinak, jen na rozdělení výpočtů, bez předávání mezi vlákny. Není to už k tomuto tématu, takže děkuji za vyřešení eventu. Teď bojuju s BackgroundWorker, zkrátka kdyby měl někdo chuť mi ještě ukázat jak se s tím robí (nebo lépe než s BW třídou), tak to uvítám, ale tuto diskuzi označuju za vyřešenou. Díky :)