Gast
2011-12-07, 14:17:53
Hallo,
ich habe eine Anwendung, die ich als ASP.NET-Webseite realisieren will, d.h. die GUI als Web-Frontend und die Backend-Logik auf dem Server laufend. Die GUI soll einen Button und ein Label enthalten, wobei der Klick auf den Button einen Thread startet, der einmal pro Sekunde eine Variable hochzählt, die dann auf dem Label ausgegeben werden soll. Als Windows-Forms-Anwendung sähe das z.B. so aus:
partial class Form1 : public System.Windows.Forms.Form
{
// deklariere Event
delegate void ProgressDelegate(int progress);
event ProgressDelegate progressEvent;
void button1_Click(object sender, EventArgs e)
{
// installiere ShowProgress() als Event handler
progressEvent += new ProgressDelegate(ShowProgress);
// starte Thread, der threadProc() ausführt
ThreadStart ts = new ThreadStart(threadProc);
Thread thread = new Thread(ts);
thread.start();
}
// Funktion, die im Thread ausgeführt wird
void threadProc()
{
for (int progress = 0; progress < 10; progress++)
{
// löse Event aus
this.Invoke(progressEvent, new object[]{progress});
// warte 1 Sekunde
Thread.Sleep(1000);
}
}
// Event handler
void ShowProgress(int progress)
{
label1.Text = progress;
}
}
Im Thread wird 10 Sekunden lang einmal pro Sekunde die Variable progress um 1 erhöht und dann der Event progressEvent ausgelöst, wodurch die Funktion ShowProgress() aufgerufen wird, die den Wert von progress auf dem Label ausgibt.
In WPF sieht es fast genauso aus, Form1 ist dann nur halt nicht von public System.Windows.Forms.Form abgeleitet, sondern von System.Windows.Window, statt this.Invoke(...) steht da Dispatcher.Invoke(...), und den Text des Labels ändert man nicht mit der Property Text, sondern mit Content.
Aber wie macht man es in ASP.NET? Form1 leitet sich dann von System.Web.UI.Page ab, soweit klar, aber wie ändert man vom Thread aus den Text des Labels? Die Page-Klasse hat keine eigene Invoke()-Methode, und eine Dispatcher-Klasse wie in der WPF-Variante gibt es auch nicht. Ich habe schon einen direkten Aufruf von ShowProgress() versucht, etwa so:
void threadProc()
{
for (int progress = 0; progress < 10; progress++)
{
ShowProgress(progress);
// warte 1 Sekunde
Thread.Sleep(1000);
}
}
was interessanterweise auch überhaupt nicht zu einem Laufzeitfehler führt, aber der Effekt ist der, dass der im Webbrowser zu sehende Text des Labels gar nicht geändert wird. Laut Debugger wird die Codezeile in ShowProgress() zwar durchlaufen, aber es hat keine Auswirkung auf den angezeigten Text des Labels.
Wie muss man das richtig machen?
Ich habe schon hier nachgesehen:
http://www.codeproject.com/Articles/38501/Multi-Threading-in-ASP-NET
was davon zu zeugen scheint, dass es für ASP.NET ein eigenes Threading-Modell abseits von System.Threading.Thread gibt. Allerdings scheint das für meine Zwecke nicht passend zu sein. Wenn ich das richtig sehe, ist die PageAsyncTask-Klasse so eine Art Pendant zur Thread-Klasse, und die Methoden BeginAsyncOperation() und EndAsyncOperation() werden beim Starten und Beenden des "Threads" ausgeführt. Was ich vermisse, ist eine Funktion, die während des asynchronen Tasks ausgeführt wird.
Ich könnte mir natürlich auch noch vorstellen, dass das, was ich vorhabe, gar nicht realisierbar ist. Allerdings würde das meiner Meinung nach der offensichtlich von Microsoft verfolgten Strategie, Webentwicklung und lokale Anwendungsentwicklung zu vereinheitlichen, widersprechen.
ich habe eine Anwendung, die ich als ASP.NET-Webseite realisieren will, d.h. die GUI als Web-Frontend und die Backend-Logik auf dem Server laufend. Die GUI soll einen Button und ein Label enthalten, wobei der Klick auf den Button einen Thread startet, der einmal pro Sekunde eine Variable hochzählt, die dann auf dem Label ausgegeben werden soll. Als Windows-Forms-Anwendung sähe das z.B. so aus:
partial class Form1 : public System.Windows.Forms.Form
{
// deklariere Event
delegate void ProgressDelegate(int progress);
event ProgressDelegate progressEvent;
void button1_Click(object sender, EventArgs e)
{
// installiere ShowProgress() als Event handler
progressEvent += new ProgressDelegate(ShowProgress);
// starte Thread, der threadProc() ausführt
ThreadStart ts = new ThreadStart(threadProc);
Thread thread = new Thread(ts);
thread.start();
}
// Funktion, die im Thread ausgeführt wird
void threadProc()
{
for (int progress = 0; progress < 10; progress++)
{
// löse Event aus
this.Invoke(progressEvent, new object[]{progress});
// warte 1 Sekunde
Thread.Sleep(1000);
}
}
// Event handler
void ShowProgress(int progress)
{
label1.Text = progress;
}
}
Im Thread wird 10 Sekunden lang einmal pro Sekunde die Variable progress um 1 erhöht und dann der Event progressEvent ausgelöst, wodurch die Funktion ShowProgress() aufgerufen wird, die den Wert von progress auf dem Label ausgibt.
In WPF sieht es fast genauso aus, Form1 ist dann nur halt nicht von public System.Windows.Forms.Form abgeleitet, sondern von System.Windows.Window, statt this.Invoke(...) steht da Dispatcher.Invoke(...), und den Text des Labels ändert man nicht mit der Property Text, sondern mit Content.
Aber wie macht man es in ASP.NET? Form1 leitet sich dann von System.Web.UI.Page ab, soweit klar, aber wie ändert man vom Thread aus den Text des Labels? Die Page-Klasse hat keine eigene Invoke()-Methode, und eine Dispatcher-Klasse wie in der WPF-Variante gibt es auch nicht. Ich habe schon einen direkten Aufruf von ShowProgress() versucht, etwa so:
void threadProc()
{
for (int progress = 0; progress < 10; progress++)
{
ShowProgress(progress);
// warte 1 Sekunde
Thread.Sleep(1000);
}
}
was interessanterweise auch überhaupt nicht zu einem Laufzeitfehler führt, aber der Effekt ist der, dass der im Webbrowser zu sehende Text des Labels gar nicht geändert wird. Laut Debugger wird die Codezeile in ShowProgress() zwar durchlaufen, aber es hat keine Auswirkung auf den angezeigten Text des Labels.
Wie muss man das richtig machen?
Ich habe schon hier nachgesehen:
http://www.codeproject.com/Articles/38501/Multi-Threading-in-ASP-NET
was davon zu zeugen scheint, dass es für ASP.NET ein eigenes Threading-Modell abseits von System.Threading.Thread gibt. Allerdings scheint das für meine Zwecke nicht passend zu sein. Wenn ich das richtig sehe, ist die PageAsyncTask-Klasse so eine Art Pendant zur Thread-Klasse, und die Methoden BeginAsyncOperation() und EndAsyncOperation() werden beim Starten und Beenden des "Threads" ausgeführt. Was ich vermisse, ist eine Funktion, die während des asynchronen Tasks ausgeführt wird.
Ich könnte mir natürlich auch noch vorstellen, dass das, was ich vorhabe, gar nicht realisierbar ist. Allerdings würde das meiner Meinung nach der offensichtlich von Microsoft verfolgten Strategie, Webentwicklung und lokale Anwendungsentwicklung zu vereinheitlichen, widersprechen.