Jak zakomunikować zmianę stanu obiektu klasy

0

Cześć,

Mam pewien problem. Nie wiem jak w mojej aplikacji zakomunikować zmianę stanu obiektu mojej klasy aby wywołać określoną akcję po stronie GUI np. wypisanie czegoś do TextBoxa.

Moja aplikacja to prosty czat internetowy składający się z klienta( Główna formatka i klasa Klient) i serwera( Główna formatka i klasa Administrator).
Działa to mniej więcej tak, że klient łączy się z serwerem. Po stronie serwera w osobnym wątku jest prowadzony nasłuch czy ktoś nie chcę dołączyć się do rozmowy jeśli tak to tworzy dynamicznie nowy wątek:

 
BackgroundWorker clientThread = new BackgroundWorker();
                            clientThread.WorkerSupportsCancellation = true;
                            clientThread.DoWork += new DoWorkEventHandler(clientThread_DoWork);

Funkcja 'clientThread_DoWork' jest prywatną funkcją klasy Administrator. Wycinek funkcji 'clientThread_DoWork':

while ((cmd = read.ReadString().Split(new char[] { ':' }))[1] != "BYE" && bw.CancellationPending == false)
                            {
                                string message = null;
                                if (cmd.Length > 2)
                                {
                                    message = cmd[2];
                                    for (int i = 3; i < cmd.Length; i++)
                                        message += " : " + cmd[i];
                                }
                                switch (cmd[1])
                                {
                                    case "SAY":

                                        //formatka.writeText(cmd[0], message);                   // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                                        sendUdpMessage(cmd[0] + ":" + cmd[1] + ":" + message + "\n");
                                        break;
                                }
                            } 

I teraz nie wiem jak wymusić na Głównej formatce żeby w momencie jak przychodzi wiadomość od klienta ta w swoim TextBoxie wypisała tą wiadomość ( //formatka.writeText(cmd[0], message); ).
Mogę na sztywno w klasie Administrator dodać pole 'private Form1 formatka;' a w klasie formatki napisać:

 public partial class Form1 : Form
    {
        Administrator admin;

        public Form1()
        {
            InitializeComponent();
            admin = new Administrator();
            admin.formatka = this;
        }
 

Wtedy wszystko działa ale czy jest zgodne z zasadą oddzielenia GUI od logiki aplikacji?

0

A od czego są eventy?
Poza tym, jesli zależy ci na tym aby oddzielić GUI od logiki to zostaw te pradawne winformsy i pisz w WPF + MVVM :P

0

W klasie formatki Form1 mam referencje do klasy Administrator

public partial class Form1 : Form
    {
        Administrator admin;
...
 

Button 'Start', który znajduje się na formatce rozpoczyna wykonywanie się wątku

 private void buttonStart_Click(object sender, EventArgs e)
        {
            try
            {
                if (admin.startServer(IPAddress.Parse(comboBoxIpAddress.Text), (int)numericUpDownPort.Value) == true)
                    backgroundWorkerMainLoop.RunWorkerAsync();
            }
...
 

Funkcja RunWorkAsynsc rozpoczyna nasłuch

 
try
            {
                setText(textBoxServer, "Serwer oczekuje na połączenie...\n");
                admin.Server.Start();
                while (true)
                {
                    admin.waitForConnection();
...

funkcja waitForConnection ( składowa funkcja klasy Administrator) sprawdza czy klient( który łączy się poprzez osobną aplikację) chcę się połączyć

 
client = server.AcceptTcpClient();
......

Jeśli tak ( to w tej samej funkcji ' waitForConnection') odpalany jest nowy wątek

 
BackgroundWorker clientThread = new BackgroundWorker();
                            clientThread.WorkerSupportsCancellation = true;
                            clientThread.DoWork += new DoWorkEventHandler(clientThread_DoWork);
clientThread.RunWorkerAsync();

Funkcją 'clientThread_DoWork' ( także składowa klasy administrator)
sprawdza czy klient chce napisać wiadomość

 
while ((cmd = read.ReadString().Split(new char[] { ':' }))[1] != "BYE" && bw.CancellationPending == false)

Jeśli tak to wywołuje funkcję 'sendUdpMessage(cmd[0] + ":" + cmd[1] + ":" + message + "\n");' która wyśle wiadomość to wszystkich klientów połączonych z serwerem( ich IP trzymam w składowej ArrayList)

Problem jest taki, że oprócz wysłania tej wiadomośći to innych userów ta wiadomość ma się również pojawić na TextBoxie formatki aplikacji administratora. ( Admin ma widzieć co kto pisze).
I teraz nie wiem jak mam przekazać tą wiadomość do formatki i powiedzieć jej "Hej, jakiś user przesyła wiadomość weź ją wpisz u siebie na TextBoxie" :D
Zastanawiam się czy rozwiązanie które pokazałem w 1 poście jest ok czy nie.

EDIT:. backgroundWorkerMainLoop to składowa klasy Form1

0

No takie rozwiązanie nie jest zbyt eleganckie.

Signum napisał(a)

A od czego są eventy?

Tutaj chodziło mi o to, żebyś użył eventu :P

0

Nie czytałem dokładnie, ale Event + klasa dziedzicząca po EventArgs żeby coś przekazać (jakieś dane) służą do informowania metod że zmienna się zmieniła itd.

0

Dzięki za pomoc, o coś takiego mi chodziło

1 użytkowników online, w tym zalogowanych: 0, gości: 1