Benutzer mit den meisten Antworten
Meldung über aktuellen Status der Anwendung

Frage
-
Hallo,
zurzeit versuche ich ein System zu entwickeln, welches Meldungen aus verschiedenen Klassen und Methoden annehmen kann und diese dann in einem Label (WPF) ausgibt.
Leider habe ich dafür noch keine so richtig brauchbare Lösung gefunden.
Hat hier jemand Tipps oder Anregungen für mich, die mir helfen würden eine Art ReportController zu erstellen?
Meine ersten Gedanken gingen an static-class und Warteschlangen-Listen. Finde nur dass meine Dinge irgendwie alle unschön gelöst wurden.
Gruß
Aaron
Antworten
-
Hi Aaron,
hier mal eine kleine Demo, damit klar wird, was ich meine:using System; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp1 { class Program12 { static void Main(string[] args) { try { Prog p1 = new Prog() { Name = "Programm 1" }; p1.Execute(); Prog p2 = new Prog() { Name = "Programm 2" }; p2.Execute(); Prog p3 = new Prog() { Name = "Programm 3" }; p3.Execute(); Console.WriteLine("Weiter, Stoppen mit beliebiger Taste"); Console.ReadKey(); p3.Stop(); p2.Stop(); p1.Stop(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } Console.WriteLine("Fertig, Abschluss mit beliebiger Taste"); Console.ReadKey(); } /// <summary> /// Klasse, die das arbeitende Programm simuliert /// </summary> internal class Prog { // Programmname internal string Name { get; set; } // Möglichkeit für Abbruch CancellationTokenSource source = new CancellationTokenSource(); CancellationToken token; // Konstruktor zur Initialisierung des Abbruch-Tokens public Prog() { token = source.Token; } // Start des Programme als separater Thread internal Task Execute() { return (new TaskFactory(token)).StartNew(Start); } // Beenden (Abbruch) des Programms internal void Stop() { source.Cancel(); } // Arbeit des Programms public async void Start() { int i = 0; while (!source.IsCancellationRequested) { i++; await Prot.Write(Name, $"Protokolleintrag {i}"); Thread.Sleep(Pause.Random); } } } /// <summary> /// Klasse, die die Protokollfunktion realisiert /// </summary> internal static class Prot { /// <summary> /// Singleton Protokoll-Klasse /// </summary> private static Protokoll p = new Protokoll(); /// <summary> /// Schreiben eines Eintrags in die Collection /// </summary> /// <param name="region">Bereichsparameter für Protokoll</param> /// <param name="msg">zu protokollierende Nachricht</param> /// <returns></returns> internal static async Task Write(string region, string msg) { await Task.Run(() => { p.Add(new ProtEintrag() { Region = region, Nachricht = msg, Zeit = DateTime.Now }); }); } /// <summary> /// Protokollklasse /// </summary> internal class Protokoll : BlockingCollection<ProtEintrag> { /// <summary> /// Hinzufügen eines zu protokollierenden Eintrages /// </summary> /// <param name="item">zu protokollierender Eintrag</param> internal protected new void Add(ProtEintrag item) { base.Add(item); are.Set(); // Anzeige, dass neuer Eintrag vorliegt } // Klassenfelder private AutoResetEvent are = new AutoResetEvent(false); private CancellationTokenSource source = new CancellationTokenSource(); private CancellationToken token; private Random rnd = new Random(); // Zufallszahl für Simulation des Zeitaufwandes /// <summary> /// Konstruktor, der den Thread für die Ablage der Protokolleinträge startet /// </summary> public Protokoll() { token = source.Token; (new TaskFactory(token)).StartNew(() => { while (true) { are.WaitOne(); while (this.Count > 0) { var eintrag = this.Take(); // Ausgabe Console.WriteLine($"{eintrag.Zeit:HH.mm.ss} {eintrag.Region} {eintrag.Nachricht}"); // Zeitaufwand für Protokollablage simulieren Thread.Sleep(rnd.Next(100, 300)); } } }); } /// <summary> /// Destructor für das Aufräumen, z.B. Datei schließen /// </summary> ~Protokoll() { // aufräumen base.Dispose(); } } } /// <summary> /// Klasse für einen Protokolleintrag /// </summary> internal class ProtEintrag { internal string Region { get; set; } internal string Nachricht { get; set; } internal DateTime Zeit { get; set; } } /// <summary> /// Hilfsklasse für eine zufällige Wartungszeit /// </summary> internal static class Pause { static Random rnd = new Random(); public static int Random { get { return rnd.Next(100, 1000); } } } } }
--
Viele Grüsse
Peter Fleischer (ehem. MVP)
Meine Homepage mit Tipps und Tricks- Als Antwort vorgeschlagen Peter Fleischer Sonntag, 9. Juli 2017 06:17
- Als Antwort markiert Triky313 Montag, 10. Juli 2017 07:32
Alle Antworten
-
Hi Aaron,
Deine Idee geht in die richtige Richtung.Baue eine statische Klasse mit einer statischen WriteProtokoll-Methode. In der Methode erzeugst Du aus den übergebenen Parametern ein Nachrichten-Objekt (z.B. mit Nachricht, Quelle, Zeit, Prozess-ID usw.). Dieses Objekt wird einer statische BlockingCollection hinzugefügt. Außerdem wird über ein Signal (z.B. AutoResetEvent) über eine neue Nachricht informiert.
Mit dem Start der Klasse (statischer Konstruktor) oder dem erstmaligen Aufruf der WriteProtokoll-Methode wird ein Thread für die Ausgabe der Protokolldaten gestartet. In diesem Thread läuft eine Schleife, die auf neue Nachrichte-Objekte wartet und dann alle vorhandenen Nachrichten-Objekte ausgibt und wieder ins Warten geht. Im Destructor kann dann die Schleife beendet und aufgeräumt werden.
--
Viele Grüsse
Peter Fleischer (ehem. MVP)
Meine Homepage mit Tipps und Tricks- Bearbeitet Peter Fleischer Samstag, 8. Juli 2017 19:16
-
Hi Aaron,
hier mal eine kleine Demo, damit klar wird, was ich meine:using System; using System.Collections.Concurrent; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp1 { class Program12 { static void Main(string[] args) { try { Prog p1 = new Prog() { Name = "Programm 1" }; p1.Execute(); Prog p2 = new Prog() { Name = "Programm 2" }; p2.Execute(); Prog p3 = new Prog() { Name = "Programm 3" }; p3.Execute(); Console.WriteLine("Weiter, Stoppen mit beliebiger Taste"); Console.ReadKey(); p3.Stop(); p2.Stop(); p1.Stop(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); } Console.WriteLine("Fertig, Abschluss mit beliebiger Taste"); Console.ReadKey(); } /// <summary> /// Klasse, die das arbeitende Programm simuliert /// </summary> internal class Prog { // Programmname internal string Name { get; set; } // Möglichkeit für Abbruch CancellationTokenSource source = new CancellationTokenSource(); CancellationToken token; // Konstruktor zur Initialisierung des Abbruch-Tokens public Prog() { token = source.Token; } // Start des Programme als separater Thread internal Task Execute() { return (new TaskFactory(token)).StartNew(Start); } // Beenden (Abbruch) des Programms internal void Stop() { source.Cancel(); } // Arbeit des Programms public async void Start() { int i = 0; while (!source.IsCancellationRequested) { i++; await Prot.Write(Name, $"Protokolleintrag {i}"); Thread.Sleep(Pause.Random); } } } /// <summary> /// Klasse, die die Protokollfunktion realisiert /// </summary> internal static class Prot { /// <summary> /// Singleton Protokoll-Klasse /// </summary> private static Protokoll p = new Protokoll(); /// <summary> /// Schreiben eines Eintrags in die Collection /// </summary> /// <param name="region">Bereichsparameter für Protokoll</param> /// <param name="msg">zu protokollierende Nachricht</param> /// <returns></returns> internal static async Task Write(string region, string msg) { await Task.Run(() => { p.Add(new ProtEintrag() { Region = region, Nachricht = msg, Zeit = DateTime.Now }); }); } /// <summary> /// Protokollklasse /// </summary> internal class Protokoll : BlockingCollection<ProtEintrag> { /// <summary> /// Hinzufügen eines zu protokollierenden Eintrages /// </summary> /// <param name="item">zu protokollierender Eintrag</param> internal protected new void Add(ProtEintrag item) { base.Add(item); are.Set(); // Anzeige, dass neuer Eintrag vorliegt } // Klassenfelder private AutoResetEvent are = new AutoResetEvent(false); private CancellationTokenSource source = new CancellationTokenSource(); private CancellationToken token; private Random rnd = new Random(); // Zufallszahl für Simulation des Zeitaufwandes /// <summary> /// Konstruktor, der den Thread für die Ablage der Protokolleinträge startet /// </summary> public Protokoll() { token = source.Token; (new TaskFactory(token)).StartNew(() => { while (true) { are.WaitOne(); while (this.Count > 0) { var eintrag = this.Take(); // Ausgabe Console.WriteLine($"{eintrag.Zeit:HH.mm.ss} {eintrag.Region} {eintrag.Nachricht}"); // Zeitaufwand für Protokollablage simulieren Thread.Sleep(rnd.Next(100, 300)); } } }); } /// <summary> /// Destructor für das Aufräumen, z.B. Datei schließen /// </summary> ~Protokoll() { // aufräumen base.Dispose(); } } } /// <summary> /// Klasse für einen Protokolleintrag /// </summary> internal class ProtEintrag { internal string Region { get; set; } internal string Nachricht { get; set; } internal DateTime Zeit { get; set; } } /// <summary> /// Hilfsklasse für eine zufällige Wartungszeit /// </summary> internal static class Pause { static Random rnd = new Random(); public static int Random { get { return rnd.Next(100, 1000); } } } } }
--
Viele Grüsse
Peter Fleischer (ehem. MVP)
Meine Homepage mit Tipps und Tricks- Als Antwort vorgeschlagen Peter Fleischer Sonntag, 9. Juli 2017 06:17
- Als Antwort markiert Triky313 Montag, 10. Juli 2017 07:32