Benutzer mit den meisten Antworten
Methode deren Fortschritt nach außen gemeldet werden soll

Frage
-
Servus,
Ich hab hier eine Methode die u.U. etwas länger dauern kann. Folglich wollte ich den internen Fortschritt der Methode nach außen melden.
Dummerweise fehlt mir dazu das Wissen. Ich hab schon recherchiert und bn zum Schluß gekommen das ich die Methode asynchron anführen muß. Also muß ich das wohl irgendwie mit delegates umsetzen und in einem eigenen Threat ausführen. Genau da hängts aber! Ich habe ein paar Beispiele im Netz gefunden aber irgendwas daran fehlt oder ist falsch.
Hier mein bisheriger Code:
// Eventhandler in der Klasse mit der Methode public event EventHandler<ProgressChangedEventArgs> ArchiveProgressChanged; // Eventhandler auslösen private void onProgressChanged(ProgressChangedEventArgs e) { if (ArchiveProgressChanged != null) ArchiveProgressChanged(this, e); } internal void Archiviere(int menge, AsyncOperation async) { int percent = 0; var eArgs = new ProgressChangedEventArgs(percent, null); async.Post(e => onProgressChanged((ProgressChangedEventArgs)e), eArgs); for (percent = 10; percent < 101; percent += 10) { eArgs = new ProgressChangedEventArgs(percent, null); Thread.Sleep(1000); async.Post(e => onProgressChanged((ProgressChangedEventArgs)e), eArgs); } }
Jetzt muß ich wahrscheinlich das ArchiveProgressChanged Ereignis abonieren:
fahrtenListe.ArchiveProgressChanged += fahrtenListeProgressChanged;
void fahrtenListeProgressChanged(object sender, ProgressChangedEventArgs e) { if (e.ProgressPercentage == 0) { // Progressbar anzeigen und auf 0 setzen } else if (e.ProgressPercentage == 100) { // Progressbar noch kurz mit 100 % anzeigen und dann ausblenden } else { // Progressbar-Wert anpassen } }
Aber wie starte ich jetzt die Methode Archiviere(int, AsyncOperation) bzw. wie muß ich den 2. Parameter angeben.
Irgendwie hänge ich mächtig fest!
Danke für jedwige Hilfe!
Gruß Roman
Antworten
-
Hallo Roman,
im Prinzip sah das schon ganz gut aus, was Du programmiert hast - und es hätte vom Prinzip her schon (mit einer winzigen Ausnahme) funktionieren können. Nur: das "async.Post" wird eben bei Dir im Main-UI Thread ausgeführt, deswegen müssen die Handler quasi warten, bis dieser Hauptthread wieder wieder frei ist, was er aber erst am Ende der Archiviere-Methode der Fall wäre.
Du kannst viele Muster (und natürlich Dein gewähltes) benutzen und es ist keineswegs auf den BackgroundWorker o.ä. beschränkt. Nur haben diese Verfahren ihre Einsatzszenarien, und ihre Vor- und Nachteile in der jeweiligen Situation.
Die Lösung ist (zum Beispiel), die relevante Stelle in einem anderen Thread (als dem HauptThread) aufzurufen, was auch ähnlich in der Doku zu AsynOperation steht. Für Dein Beispiel mal rudimentär:
Form1.cs:using System; using System.ComponentModel; using System.Windows.Forms; namespace WinEventAsyncDemo { public partial class Form1 : Form { ProgressBar progressBar1 = new ProgressBar(); Fahrten fahrtenListe = new Fahrten(); public Form1() { InitializeComponent(); progressBar1.Width = Width - 20; Controls.Add(progressBar1); } void Fahrten_ArchiveProgressChanged(object sender, ProgressChangedEventArgs e) { if (e.ProgressPercentage == 0) { progressBar1.Visible = true; // Progressbar anzeigen und auf 0 setzen } else if (e.ProgressPercentage == 100) { progressBar1.Value = 100; progressBar1.Enabled = false; // Progressbar noch kurz mit 100 % anzeigen und dann ausblenden } else { progressBar1.Value = e.ProgressPercentage; } } private void Form1_Shown(object sender, EventArgs e) { fahrtenListe.ArchiveProgressChanged += Fahrten_ArchiveProgressChanged; fahrtenListe.Archiviere(50); } } }
____________________________
Fahrten.cs:using System; using System.ComponentModel; using System.Threading; namespace WinEventAsyncDemo { class Fahrten { public Fahrten() { AsyncOp = AsyncOperationManager.CreateOperation(null); } public AsyncOperation AsyncOp { get; set; } public event EventHandler<ProgressChangedEventArgs> ArchiveProgressChanged; private void OnProgressChanged(ProgressChangedEventArgs e) { if (ArchiveProgressChanged != null) ArchiveProgressChanged(this, e); } public void Archiviere(int menge) { Thread workerThread = new Thread(new ParameterizedThreadStart(ArchiviereImThread)); workerThread.Start((object)menge); } private void ArchiviereImThread(object menge) { int percent = 0; var eArgs = new ProgressChangedEventArgs(percent, null); SendOrPostCallback callback = e => OnProgressChanged((ProgressChangedEventArgs)e); AsyncOp.Post(callback, eArgs); for (percent = 10; percent < 101; percent += 10) { eArgs = new ProgressChangedEventArgs(percent, null); Thread.Sleep(1000); SendOrPostCallback callback2 = e => OnProgressChanged((ProgressChangedEventArgs)e); AsyncOp.Post(callback2, eArgs); } } } }
____________________________
Funktionierende Beispiel mit AsyncOperation gibt es ja in der Doku und vielen anderen Artikeln.
[The .NET Framework's New SynchronizationContext Class - CodeProject]
http://www.codeproject.com/KB/cpp/SyncContextTutorial.aspx[Asynchronous Method Progress Reporting [C#]]
http://www.csharp-examples.net/asynchronous-method-progress/Grundsätzliche Überlegungen zum Thread-Wechsel:
[Bearbeiten von Steuerelementen aus Threads]
http://dzaebel.net/ControlInvoke.htm[Gewusst wie: Implementieren eines Clients des ereignisbasierten asynchronen Musters]
http://msdn.microsoft.com/de-de/library/8wy069k1.aspxFür einen FTP-Uplaod hatte ich einmal folgende Methode benutzt:
[FTP Upload mit Byte-Anzeige]
http://dzaebel.net/FtpUpload.htm
ciao Frank- Als Antwort markiert Roman Faust Sonntag, 20. Februar 2011 22:43
Alle Antworten
-
Hallo Roman,
wenn du Rückmeldungen von einem Thread benötigst, so verwende einfach "System.ComponentModel.BackgroundWorker". (http://msdn.microsoft.com/de-de/library/system.componentmodel.backgroundworker.aspx).
BackgroundWorker ist im Prinzip eine Threadklasse, die bereits einen Mechanismus verfügt, um mit einem anderen Thread zu kommunizieren (z.B. um den Fortschritt seiner Arbeit zu melden etc.)
Ich hoffe ich konnte dir weiterhelfen. Ansonsten bitte gezielt nachfragen...
Viele Grüße
Holger M. Rößler- Bearbeitet Holger M. Rößler Samstag, 19. Februar 2011 22:45 Format
-
Hi ,
entweder du arbeitest nur mit Events und lässt deine Form (WinForms Invoke, WPF Dispatcher) die events auslesen(Zb progressChanged und ein OnEnd event) oder du nutzt zB . http://www.csharp-examples.net/create-asynchronous-method/. Dort steht genau drin wie man Asynchrone Operationen ausführt.
-
Hallo Roman,
im Prinzip sah das schon ganz gut aus, was Du programmiert hast - und es hätte vom Prinzip her schon (mit einer winzigen Ausnahme) funktionieren können. Nur: das "async.Post" wird eben bei Dir im Main-UI Thread ausgeführt, deswegen müssen die Handler quasi warten, bis dieser Hauptthread wieder wieder frei ist, was er aber erst am Ende der Archiviere-Methode der Fall wäre.
Du kannst viele Muster (und natürlich Dein gewähltes) benutzen und es ist keineswegs auf den BackgroundWorker o.ä. beschränkt. Nur haben diese Verfahren ihre Einsatzszenarien, und ihre Vor- und Nachteile in der jeweiligen Situation.
Die Lösung ist (zum Beispiel), die relevante Stelle in einem anderen Thread (als dem HauptThread) aufzurufen, was auch ähnlich in der Doku zu AsynOperation steht. Für Dein Beispiel mal rudimentär:
Form1.cs:using System; using System.ComponentModel; using System.Windows.Forms; namespace WinEventAsyncDemo { public partial class Form1 : Form { ProgressBar progressBar1 = new ProgressBar(); Fahrten fahrtenListe = new Fahrten(); public Form1() { InitializeComponent(); progressBar1.Width = Width - 20; Controls.Add(progressBar1); } void Fahrten_ArchiveProgressChanged(object sender, ProgressChangedEventArgs e) { if (e.ProgressPercentage == 0) { progressBar1.Visible = true; // Progressbar anzeigen und auf 0 setzen } else if (e.ProgressPercentage == 100) { progressBar1.Value = 100; progressBar1.Enabled = false; // Progressbar noch kurz mit 100 % anzeigen und dann ausblenden } else { progressBar1.Value = e.ProgressPercentage; } } private void Form1_Shown(object sender, EventArgs e) { fahrtenListe.ArchiveProgressChanged += Fahrten_ArchiveProgressChanged; fahrtenListe.Archiviere(50); } } }
____________________________
Fahrten.cs:using System; using System.ComponentModel; using System.Threading; namespace WinEventAsyncDemo { class Fahrten { public Fahrten() { AsyncOp = AsyncOperationManager.CreateOperation(null); } public AsyncOperation AsyncOp { get; set; } public event EventHandler<ProgressChangedEventArgs> ArchiveProgressChanged; private void OnProgressChanged(ProgressChangedEventArgs e) { if (ArchiveProgressChanged != null) ArchiveProgressChanged(this, e); } public void Archiviere(int menge) { Thread workerThread = new Thread(new ParameterizedThreadStart(ArchiviereImThread)); workerThread.Start((object)menge); } private void ArchiviereImThread(object menge) { int percent = 0; var eArgs = new ProgressChangedEventArgs(percent, null); SendOrPostCallback callback = e => OnProgressChanged((ProgressChangedEventArgs)e); AsyncOp.Post(callback, eArgs); for (percent = 10; percent < 101; percent += 10) { eArgs = new ProgressChangedEventArgs(percent, null); Thread.Sleep(1000); SendOrPostCallback callback2 = e => OnProgressChanged((ProgressChangedEventArgs)e); AsyncOp.Post(callback2, eArgs); } } } }
____________________________
Funktionierende Beispiel mit AsyncOperation gibt es ja in der Doku und vielen anderen Artikeln.
[The .NET Framework's New SynchronizationContext Class - CodeProject]
http://www.codeproject.com/KB/cpp/SyncContextTutorial.aspx[Asynchronous Method Progress Reporting [C#]]
http://www.csharp-examples.net/asynchronous-method-progress/Grundsätzliche Überlegungen zum Thread-Wechsel:
[Bearbeiten von Steuerelementen aus Threads]
http://dzaebel.net/ControlInvoke.htm[Gewusst wie: Implementieren eines Clients des ereignisbasierten asynchronen Musters]
http://msdn.microsoft.com/de-de/library/8wy069k1.aspxFür einen FTP-Uplaod hatte ich einmal folgende Methode benutzt:
[FTP Upload mit Byte-Anzeige]
http://dzaebel.net/FtpUpload.htm
ciao Frank- Als Antwort markiert Roman Faust Sonntag, 20. Februar 2011 22:43
-
Hallo Roman,
im Prinzip sah das schon ganz gut aus, was Du programmiert hast - und es hätte vom Prinzip her schon (mit einer winzigen Ausnahme) funktionieren können. Nur: das "async.Post" wird eben bei Dir im Main-UI Thread ausgeführt, deswegen müssen die Handler quasi warten, bis dieser Hauptthread wieder wieder frei ist, was er aber erst am Ende der Archiviere-Methode der Fall wäre.
Du kannst viele Muster (und natürlich Dein gewähltes) benutzen und es ist keineswegs auf den BackgroundWorker o.ä. beschränkt. Nur haben diese Verfahren ihre Einsatzszenarien, und ihre Vor- und Nachteile in der jeweiligen Situation.
Die Lösung ist (zum Beispiel), die relevante Stelle in einem anderen Thread (als dem HauptThread) aufzurufen, was auch ähnlich in der Doku zu AsynOperation steht. Für Dein Beispiel mal rudimentär:
Herzlichen Dank Frank!
Wie immer sehr hilfreich Deine Antwort. Mit Threads hatte ich halt noch nie intensiver zu tun. Da fehlt noch viel. Bisher hatte immer ein Backgroundworker gereicht aber diesmal wollte ichs mal richtig machen.
Gruß Roman