Toon posts:

[C#] Nieuw window openen, thread loopt vast?

Pagina: 1
Acties:
  • 175 views sinds 30-01-2008
  • Reageer

Verwijderd

Topicstarter
Hey,

Allereerst natuurlijk nog de beste wensen! Kzal eens proberen uit te leggen wat er aan de hand is, kon hier niets vinden op google..

Kheb een chat programma, waar je een main form hebt en dus chatforms. Je kunt je contacten zien in een lijst, dat werkt allemaal prima, je kunt ook op een contact dubbelklikken, en dan opent ie netjes een nieuw chatwindow dmv de volgende code:

(Sorry van de lappen code.. deze code klopt gewoon verder.. maar om het 1 en ander duidelijk te maken)

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private void contactlist_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            frmChatwindow tempWindow;
            frmChatwindow Window;

            if (contactlist.ContactsWindows.ContainsKey(contactlist.SelectedItem.ToString()))
            {
                tempWindow = (frmChatwindow)contactlist.ContactsWindows[contactlist.SelectedItem.ToString()];

                try
                {
                    tempWindow.Show();
                    tempWindow.Focus();
                }
                    //De window staat in de hashlist, maar is er blijkbaar niet
                catch
                {
                    Window = newWindow(contactlist.SelectedItem.ToString(), contactlist.ContactsNames[contactlist.SelectedItem.ToString()].ToString());
                    
                    contactlist.ContactsWindows.Remove(contactlist.SelectedItem.ToString());
                    contactlist.ContactsWindows.Add(contactlist.SelectedItem.ToString(),Window);
                }

            } else {

                Window = newWindow(contactlist.SelectedItem.ToString(), contactlist.ContactsNames[contactlist.SelectedItem.ToString()].ToString());

                contactlist.ContactsWindows.Add(contactlist.SelectedItem.ToString(), Window);
                Window.Show();
            }
        }


De functie newwindow is niets anders als dit:

code:
1
2
3
4
5
6
7
8
9
10
public frmChatwindow newWindow(string ID, string Nickname)
        {
            frmChatwindow Window;

            Window = new frmChatwindow(ID, Nickname);
            Window.SendMessage += new SendMessageEventHandler(SendMessage);
            //Window.Closing += new ClosingEventHandler(WindowClosing);

            return Window;
        }


De contstructor in de frmChatwindow zorgt ervoor dat hij ID en Nickname even snel processed:

code:
1
2
3
4
5
6
7
8
9
10
public frmChatwindow(string tempID, string tempNickname)
        {
            InitializeComponent();

            ID = Convert.ToInt32(tempID);
            Nickname = tempNickname;
            this.lblNickname.Text = Nickname;
            this.Text = Nickname;
            //this.Show();
        }


Dit om even duidelijk te maken dat (hopelijk) hier alles klopt en er geen vragen achteraf komen van, wat is dat, en dat...

ID is inderdaad een string, maar dat is om niet constant te hoeven converten naar integers, gek genoeg hoeft dat nergens echt, alleen maar om dingen te checken in de hashlist. In deze hashlist heb ik alle IDs (account IDs eigenlijk) op een lijstje staan, met daaraan een window verbonden. Bestaat er een ID Key niet, is er dus geen window en moet er een nieuwe window komen. Komt er een bericht binnen, even de window opzoeken in de hashtable (aan de hand van een ID) en het bericht plaatsen in de window.

Berichten krijg ik binnen op een andere thread, in een while loop. Als ik een bericht binnen krijg, checkt ie eerst of er al een window bestaat, zo ja, dan stuurt ie het bericht door naar die window (uit de hashlist). Dit gedeelte werkt. Wat echter niet werkt is als er een bericht binnenkomt voor een ID wat nog niet in die hashlist staat en ik dus een nieuw window moet aanmaken.

Hier de code voor een inkomend bericht:

Data(0) is de code 11, Data(1) is het ID van degene het afkomt, en Data(2) is het bericht zelf:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
case 11:
                            frmChatwindow tempWindow;
                            
                            if (contactlist.ContactsWindows.ContainsKey(data.GetValue(1).ToString()))
                            {
                                tempWindow = (frmChatwindow)contactlist.ContactsWindows[data.GetValue(1).ToString()];
                                tempWindow.chatMessage(data.GetValue(2).ToString());
                            }
                            else
                            {
                                tempWindow = newWindow(data.GetValue(1).ToString(), contactlist.ContactsNames[data.GetValue(1).ToString()].ToString());

                                addContactWindow(data.GetValue(1).ToString(), tempWindow);
                                tempWindow.Show();                                
                            }
                            break;


Het gaat dus om die laatste else, daar moet ik sowieso een addContactWindow maken ipv direct naar de hashlist iets gooien, vanwege crossthread execution. Maar als ik nu tempWindow.Show() aanroep, komt er een nieuw window, maar blijft die window meteen hangen.

Wat ik heb geprobreerd is een nieuwe thread voor die show te maken, maar dit werkt ook niet. Ik weet echt niet wat er hier aan de hand is, ben er al een halve dag (naja.. nie constant :9 ) mee bezig maar om 1 of andere reden blijft de form daar keihard hangen. Ik heb ook geprobeerd het in de contsructor van de form een show uit te voeren, maar hetzelfde resultaat... Mijn vermoeden is (omdat het contstante while loop is), is dat hij blijft hangen vanwege de while loop en de Read functie van de socket. Daarbij blijft de thread hangen.

Maar als ik een nieuwe thread maak, die de Show aanroept, of zelfs een aparte thread voor newWindow (met parameterizedstartThread) gebeurt er ook niet veel...

Ik denk zelf dat ik verder niet moet gaan klooien met threads, lijkt me nergens voor nodig.. maar ik zou niet weten wat ik dan wel moet doen... hij blijft gewoon hangen vanwege die socket.read() in de while loop...

Dusss.. iemand een idee hoe ik goed en veilig een nieuwe window kan maken zonder dat de window zijn thread stopt???

Dank! _/-\o_

(en ja.. ik weet het, zei het al.. veel code.. maar alleen om duidelijk te maken..)

  • LordLarry
  • Registratie: Juli 2001
  • Niet online

LordLarry

Aut disce aut discede

Zonder naar je code te kijken: Stop met UI te mixen in je thread. Laat de UI in de main thread en maak je thread code zonder direct de UI aan te spreken. Nog beter: Splits de UI en de business logic. Met andere woorden: Zorg dat je code niet afhankelijk is van allerlei UI onderdelen.

Zie http://www.gekko-software.nl/DotNet/Art05.htm

[ Voor 9% gewijzigd door LordLarry op 04-01-2006 19:04 ]

We adore chaos because we like to restore order - M.C. Escher


Verwijderd

Topicstarter
LordLarry schreef op woensdag 04 januari 2006 @ 19:03:
Zonder naar je code te kijken: Stop met UI te mixen in je thread. Laat de UI in de main thread en maak je thread code zonder direct de UI aan te spreken. Nog beter: Splits de UI en de business logic. Met andere woorden: Zorg dat je code niet afhankelijk is van allerlei UI onderdelen.

Zie http://www.gekko-software.nl/DotNet/Art05.htm
Dat heb ik ongeveer al.. Maar dat verhelpt het probleem niet...

  • whoami
  • Registratie: December 2000
  • Laatst online: 18:20
Zoals LordLarry al zegt moet je ervoor zorgen dat je je UI code en je thread code niet mixt.
Je thread mag je UI niet rechtstreeks aanspreken. Enkel de thread die de UI controls gemaakt heeft, mag deze wijzigen.


Dit is een manier om die problematiek op te lossen (dmv Invoke dus)
[rml]whoami in "[ C#] button.Show() vanuit anderen Thread"[/rml]

Dat nieuwe window moet je dus niet in die thread maken, maar in je UI thread.

https://fgheysels.github.io/


Verwijderd

Topicstarter
Dus ik zou die newWindow moeten invoken.. kdacht dat ik dat al had geprobeert :S Ik zal het zo ff doen, bedankt iig :)

Verwijderd

Topicstarter
Hmm.. ik volg het echt niet meer ff.. ik heb nu dit:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void newWindow(string ID, string Nickname)
        {
            doNewWindowCallback d = new doNewWindowCallback(newWindowInvoked);
            Invoke(d, new object[] { ID, Nickname });
        }

        public void newWindowInvoked(string ID, string Nickname)
        {
            frmChatwindow Window;

            Window = new frmChatwindow(ID, Nickname);
            Window.SendMessage += new SendMessageEventHandler(SendMessage);
            //Window.Closing += new ClosingEventHandler(WindowClosing);

            contactlist.ContactsWindows.Add(contactlist.SelectedItem.ToString(), Window);
            Window.Show();
        }


Met deze delegate:

code:
1
delegate void doNewWindowCallback(string ID, string Nickname);


Maar als ik hem uitvoer krijg ik deze error:

(op het moment bij het krijgen van een bericht waarbij de window nog niet bestaat en alleen dan krijg ik deze error)

Object reference not set to an instance of an object.

op deze regel:

code:
1
Invoke(d, new object[] { ID, Nickname });


Hij zegt dat ik new moet gebruiken.. maar hoe dan :?

  • whoami
  • Registratie: December 2000
  • Laatst online: 18:20
Maak een event die uitgevoerd wordt als er een nieuw bericht binnenkomt.

In de event-handler voor dat event, ga je dan een nieuw window gaan aanmaken.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class MessageHandler
{
     public void Start()
     {
          // starts the message handling on a new thread.
          Thread t = new Thread(Bliep);
          t.Start();
     }

     private void Bliep()
     {
           while( _cancel == false )
           {
               if( newmessagereceived )
               {
                    OnNewMessageRecevied();
               }
           }
     }

     private void OnNewMessageReceived()
     {
           if( myEvent != null )
           {
                // voer hier het event op een veilige manier uit (zie m'n eerdere link).
           }
     }
}


Deze class kan je dus oproepen vanuit je windows applicatie, en, voor je de taak start, hang je een aantal eventhandlers aan de nodige events. Bv, een eventhandler aan de event 'newmessagereceived', die een nieuw window toont.

https://fgheysels.github.io/


Verwijderd

Topicstarter
WOJOW!!

Eureka!

Na die eventhandler te hebben gemaakt + een invoke werkt het gedoetje :*)

Tziet er gelikt uit :+

Thanks Whoami! _/-\o_

[ Voor 3% gewijzigd door Verwijderd op 04-01-2006 22:07 ]


  • Bint
  • Registratie: Juli 2002
  • Laatst online: 14:52
bluetje, zou ik eens jouw code mogen bekijken hoe jij het hebt gedaan? ;)

Memories of yesterday, will grow, but never die


Verwijderd

Topicstarter
Bintje schreef op Friday 06 January 2006 @ 16:48:
bluetje, zou ik eens jouw code mogen bekijken hoe jij het hebt gedaan? ;)
Ehm.. jah.. maar ik kan je geen PM oid sturen.. hoe werkt dat precies in GOT ? Mag je dan hier een email neerzetten ? (Edit: Kon nix in rules vinden...)

[ Voor 6% gewijzigd door Verwijderd op 07-01-2006 14:45 ]


  • Bint
  • Registratie: Juli 2002
  • Laatst online: 14:52
mijn email:


Ik heb je mail-adres maar ff weggehaald, je kan je email adres ook in je profiel zetten. Da's zowiezo veiliger.

[ Voor 115% gewijzigd door whoami op 08-01-2006 13:19 ]

Memories of yesterday, will grow, but never die


  • Bint
  • Registratie: Juli 2002
  • Laatst online: 14:52
heb em er nu in gezet..

Memories of yesterday, will grow, but never die

Pagina: 1