C# WebClient Thread terminiert nicht?

XHotSniperX

Lt. Junior Grade
Registriert
Jan. 2008
Beiträge
474
Hallo

ich möchte eine XML Datei aus dem Internet Laden in einem Thread und während des Ladens soll der Inhalt des Buttons sich zu "Lädt..." verwandeln und sobald der Thread fertig ist, soll dann auf dem Button "Aktualisieren" stehen.

Dass sich der Inhalt des Buttons nicht verändert, liegt wahrcheinlich an dem Freeze des Hauptprogramms während des Joins(). Aber das schlimmere Problem ist, dass der Thread irgendwie garnicht beendet wird und somit das Programm einfach einfriert bei Join.

Mein Ziel ist einfach eine ganz einfache Nachricht während des Ladens, damit man weiss, es wird geladen.

Wieso beendet der Thread nicht?

Code:
        private static XElement doc;
        public static void LoadXmlItems()
        {
            WebClient client = new WebClient();
            String xmlURL = "http://xxxx.xml";
            client.OpenReadCompleted += new OpenReadCompletedEventHandler(Completed);
            client.OpenReadAsync(new Uri(xmlURL, UriKind.Absolute));
        }

        private static void Completed(object sender, OpenReadCompletedEventArgs e)
        {
            if (e.Error != null)
                return;

            Stream str = e.Result;
            doc = XElement.Load(str);
            str.Close();
        }


        private void button1_Click(object sender, RoutedEventArgs e)
        {
            button1.Content = "Lädt...";     //Button-Inhalt ändert sich nicht. Wegen Freeze?     
            Thread t = new Thread(LoadXmlItems);
            t.Start();
            t.Join();  //Geht nicht weiter...
            xmlLoaded();
            button1.Content = "Aktualisieren"; //Button-Inhalt ändert sich nicht. Wegen Freeze?
        }

Wäre dankbar für Tipps :)
 
Müsste es nicht "button.Text = "hierdeintext";" heißen und nicht "button.Content = "hierdeintext";" ?

Das wird dein Hauptproblem mit dem Freeze zwar nicht lösen, aber jetzt sollte sich der Text des Buttons wenigstens ein mal ändern. Warum dein Programm einfriert weiss ich leider auch grade nicht...
 
@Kyro0
Nein muss es nicht, er benutzt wahrscheinlich einen System.Windows.Controls.Button und keinen System.Windows.Forms.Button.

@XHotSniperX
Du hast 2 sehr große Böcke in deinem Code:

1. In Z.23 änderst du den Button Inhalt, was aber völlig sinnlos ist, da du ihn in Z.28 nochmal änderst.
Der Button Inhalt wird erst aktualisiert, wenn die button1_Click()_Methode verlassen wird, also geht Z.23 quasi einfach unter.

2. Dein Hauptroblem und (sorry) ganz ganz großer Scheiß:
Du spawnst einen neuen Thread, in dem LoadXmlItems() ausgeführt wird.
Im Normalfall ist LoadXmlItems() aber quasi sofort fertig, da sie nicht wartet, bis die Datei fertig runtergeladen ist, sondern den Download startet und dann terminiert.
Du benutzt nämlich OpenReadAsync(). Das Async steht für asynchronous, d.h. es wird ein Thread für den Download benutzt.
Wenn jetzt in LoadXmlItems() auch noch eine Exception auftritt, dann freezt dein Programm, weil es ja dank Thread.Join() wartet bis LoadXmlItems() abgearbeitet ist solange, bis sich der VS Debugger dann mal erbarmt und dich auf die Exception hinweist.


Dein Problem kannst du lösen wenn dein button_Click so aussieht:
Code:
private void button1_Click(object sender, RoutedEventArgs e)
{
     button1.Content = "Lädt...";
     LoadXmlItems()
}
Alles was du erst ausführen willst, wenn der Stream geöffnet ist, kommt logischerweise in den OpenReadCompletedEventHandler.
 
hey danke für die tipps. hat geklappt :)
Ergänzung ()

Scheint gut zu klappen EIGENTLICH. Jetzt wird aber der Prozessor richtig ausgelastet und es fängt an zu stocken, wenn man paar mal auf den Button klickt. Wieso das jetzt? Werden die WebClients irgendwie nicht geschlossen?
 
Natürlich werden die nicht disposed, wenn du es nicht machst.
Du solltest auch nicht für jeden Download nen extra WebClient anlegen, sondern am besten immer den gleichen benutzen.

Erstelle doch den WebClient im Konstruktor deiner Klasse und abonniere da auch gleich die Events.
Du solltest dann in deine Klasse auch IDisposable implementieren und beim Aufruf von Dispose() dann die Resourcen des WebClient freigeben (client.Dispose()).
 
Naja also nur durch die paar Webclient Instanzen sollte der Prozessor nicht in die Knie gehen. Ohne Dispose werden sie halt vielleicht nicht unmittelbar freigegeben, das macht aber nichts aus. Ich denke die Ursachen liegen da woanders.
 
Zuletzt bearbeitet:
Trotzdem sollte er erstmal die elementarsten Fehler in seinem Code beheben bevor er weitermacht und es ist auf jeden Fall auch nicht schlecht schonmal was von IDisposable gehört zu haben.

Ohne weiteren Code zu sehen kann man auch nicht mehr sagen als dass mehrere WebClient Instanzen in diesem Fall einfach nicht nötig sind.
 
Ok den Fehler konnte ich finden. Lag wirklich wo anders. Wenn ich jetzt nur einen WebClient benutze und nach einer Benutzung ihn mit einer anderen Methode nochmal benutzen möchte, ist irgendwie der String vom letzten Mal immer noch da drin.. Wie kann ich das cleanen nach jeder Bunutzung? Mit diesem Dispose?

Mit zwei WebClients funktioniert es.
 
Zuletzt bearbeitet:
Nein, Dispose mach das Objekt unbenutzbar. Das sagt quasi bescheid, dass das Objekt gelöscht werden kann. Passiert normalerweise komplett automatisch, ist vor allem bei performancekritischen Anwendungen und Spezialfällen von Bedeutung das explizit zu steuern.
Zu deinem Problem jetzt: Also wenn der vorherige Call wirklich abgeschlossen ist, also der Stream geschlossen etc., sollte es funktionieren einfach openreadasync auf eine neue Uri zu callen. Sicher das du callst nachdem das Completed Event geschmissen wurde? Ansonsten würd ich, wenn du nich eine Queue im Code mit einem Client abarbeitest, einfach einen neuen erstellen (wenn das dann nicht in tausende WebClients ausartet ;)). Aber was willst du denn konkret machen?
 
Zuletzt bearbeitet:
Ja bin mir eigentlich sicher, dass die Completed Methoden aufgerufen werden.. aber egal ich habe jetzt konstant zwei webclients und damit funktioniert es auch. naja ich hab einen rss reader gemacht und einen serveronline checker :)
 
Zurück
Oben