Benutzer mit den meisten Antworten
[windows forms] event in event

Frage
-
Hallo Forum,
ich habe eine Klasse DB_Import, welche alle Ausgaben in die Konsole schreibt. Nun möchte ich dieser Klasse ein WinForms GUI verpassen. Dabei soll DB_Import möglichst gekapselt (also unabhängig vom Rest des WinForms Programms) sein.
- Auf einen ButtonClick hin soll die StartImport()-Methode der DB_Import-Klasse gestartet werden.
- Außerdem möchte ich alle Console.WriteLines("Nachricht") durch events ersetzen: also event("Nachricht") --> ShowMyMessage(string message) {listbox1.Items.Add(message);}
Leider hagelt es Fehlermeldungen, wenn ich folgendes versuche: (folgender Code ist per Hand eingetippt, kann also Schreibfehler beinhalten)
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace WindowsApplication2 { public partial class Form1 : Form { public Form1() { InitializeComponent(); Text = "MyImport V0.0" } private void button1_Click(object sender, EventArgs e) { DB_Import.StartImport(); } public static void ShowNotification(string notificationStr)
{
MessageBox.Show(notificationStr);
//besser: listBox1.Items.Add(notificationStr); //listBox1 ist aber nicht sichtbar, warum
} } class DB_Import { public DB_Import() {}
public delegate void Notify (strig notificationStr);
public event Notify notifier = new Notify(Form1.ShowNotification);
public void StartImport() {
//lots of DB-Code
//...
notifier("Instead of Console.WriteLine"); } } }
Wie müsste ich das Programm strukturieren, damit es wie gewünscht funktioniert?
MfG Flux
- Bearbeitet Flux1989 Montag, 6. August 2012 09:19
Antworten
-
Hallo, erstmal was grundsätzliches zu den EventHandlern, diese haben immer folgende Syntax:
Methodenname(object sender, EventArgs e){/*...*/}
so wie bei deinem
button1_Click(object sender, EventArgs e)
Eventhandler.
In der Klasse DBImport würde ich an deiner Stelle eine eigene, von EventArgs abgeleitete Klasse implementieren und diese im Event übergeben.
public partial class Form1 : Form { MyClass mc = new MyClass(); //Deine Klasse instanzieren public Form1() { InitializeComponent(); mc.ThrowedEvent += mc_ThrowedEvent; mc.DoEvent(); //Event erzeugen } void mc_ThrowedEvent(object sender, MyEventArgs e) { MessageBox.Show(e.String); } } class MyClass { public MyClass() { } public event EventHandler<MyEventArgs> ThrowedEvent; public void DoEvent() { if (ThrowedEvent != null) //Überprüfen ob das Event abbonniert ist ThrowedEvent(this, new MyEventArgs("Meldung")); //Event auslösen mit dieser Instanz un ddeinen Parametern } } class MyEventArgs : EventArgs //Eiegne Eventsklasse für deinen String { public readonly string String; public MyEventArgs(string s) { this.String = s; } }
Der Code dürfte die reine Funktionalität darstellen, musst du natürlich entsprechend übersetzen und anpassen.
Du kannst natürlich auch über einen Delegaten arbeiten, aber ich bevorzuge diese Variante.Koopakiller - http://koopakiller.ko.ohost.de/
- Als Antwort markiert Flux1989 Montag, 6. August 2012 15:24
Alle Antworten
-
Um innerhalb von Form1.ShowNotification() auf Form1.listBox1 zugreifen zu können, sagt mir der debugger ich müsse Form1 instanziieren.. hm, ok. Also ändere ich Form1.ShowNotification() folgendermaßen:
public static void ShowNotification(string notificationStr) { Form1 f1 = new Form1(); f1.listBox.Items.Add(notificationStr); }
Problem: Wenn ich das Programm ausführe und auf button1 klicke, dann bleibt listBox1 leer, warum?? -
Hallo, erstmal was grundsätzliches zu den EventHandlern, diese haben immer folgende Syntax:
Methodenname(object sender, EventArgs e){/*...*/}
so wie bei deinem
button1_Click(object sender, EventArgs e)
Eventhandler.
In der Klasse DBImport würde ich an deiner Stelle eine eigene, von EventArgs abgeleitete Klasse implementieren und diese im Event übergeben.
public partial class Form1 : Form { MyClass mc = new MyClass(); //Deine Klasse instanzieren public Form1() { InitializeComponent(); mc.ThrowedEvent += mc_ThrowedEvent; mc.DoEvent(); //Event erzeugen } void mc_ThrowedEvent(object sender, MyEventArgs e) { MessageBox.Show(e.String); } } class MyClass { public MyClass() { } public event EventHandler<MyEventArgs> ThrowedEvent; public void DoEvent() { if (ThrowedEvent != null) //Überprüfen ob das Event abbonniert ist ThrowedEvent(this, new MyEventArgs("Meldung")); //Event auslösen mit dieser Instanz un ddeinen Parametern } } class MyEventArgs : EventArgs //Eiegne Eventsklasse für deinen String { public readonly string String; public MyEventArgs(string s) { this.String = s; } }
Der Code dürfte die reine Funktionalität darstellen, musst du natürlich entsprechend übersetzen und anpassen.
Du kannst natürlich auch über einen Delegaten arbeiten, aber ich bevorzuge diese Variante.Koopakiller - http://koopakiller.ko.ohost.de/
- Als Antwort markiert Flux1989 Montag, 6. August 2012 15:24
-
Es gibt mehrere Möglichkeiten, um eine Information aus dem Objekt an den Nutzer zu übergeben:1. Du teilst dem Objekt eine Referenz auf das aufrufende Objekt mit, z.B. im Konstruktor übergibst Du this als Verweis auf das Form1-Objekt. Damit kannst Du dann auf alle Innereien von Form1 zugreifen. Diese Lösung ist nicht optimal, da Dein Objekt den Typ (=Klasse) “Form1” kennen muss.2. Eine im Objekt aufgerufene Methode gibt als Rückgabewert Information zurück.3. Der Aufrufer fragt eine Eigenschaft des Objektes ab, um sich damit Information über den Zustand des Objektes zu holen.4. Dem Objekt wird ein Delegate übergeben, den das Objekt für einen “Rückruf” nutzt, um beim “Rückruf” Information zurückzusenden.5. Dein Objekt bietet ein Ereignis (event), welches das Objekt auslösen kann, um einen neuen Zustand zu signalisieren. Derjenige, der das Ereignis abonniert hat, kann sich entweder den neuen Zustand durch Auslesen (analog 3.) abholen, oder bekommt die Information über die Ereignisargumente in der Ereignisroutine geliefert.--
Viele Gruesse
Peter -
Danke euch. Allerdings erhalte ich folgende Fehlermeldung:
Fehler 1 Inkonsistenter Zugriff: Parametertyp "WindowsApplication2.MyEventArgs" ist weniger
zugreifbar als Methode "WindowsApplication2.Form1.ShowNotification(object, WindowsApplication2.MyEventArgs)"
C:\Users\JB\Documents\Visual Studio 2005\Projects\WindowsApplication2\WindowsApplication2\Form1.cs
26 28 WindowsApplication2
Hier mein Code:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; namespace WindowsApplication2 { public partial class Form1 : Form { DB_Import it = new DB_Import(); public Form1() { InitializeComponent(); Text = "Import src2dst V 0.9"; // it.ThrownEvent += it_ShowNotification; //ThrownEvent(this, new MyEventArgs("Instead of Console.WriteLine")); } public static void ShowNotification(object sender, MyEventArgs e) { MessageBox.Show(e.EventString); //Form1 f1 = new Form1(); // f1.listBox1.Items.Add(notificationStr); } private void button1_Click(object sender, EventArgs e) { it.StartImport(); } } class DB_Import { public DB_Import() { } public event EventHandler<MyEventArgs> ThrownEvent = new EventHandler<MyEventArgs>(Form1.ShowNotification); public void StartImport() { //lots of DB-Code... ThrownEvent(this, new MyEventArgs("Instead of Console.WriteLine")); } } class MyEventArgs : EventArgs { public readonly string EventString; public MyEventArgs(string s) { this.EventString = s; } } }
-
Hallo,
das liegt daran, das die Methode
ShowNotification
public ist und ein Objekt von
MyEventArgs
braucht, welche außerhalb des Namespaces nicht sichbar ist, also deklariere deine Klasse als public:
public class MyEventArgs {
Koopakiller - http://koopakiller.ko.ohost.de/
-
Danke!
Wenn du mir jetzt noch verraten könntest, warum listBox1.Items.Add(e.EventString) in ShowNotification nicht aufrufbar ist ?
Der Versuch Form1 zu instanziieren, um dann auf listBox1 zuzugreifen bringt zwar keinen Fehler, aber listBox1 bleibt nach button1.Click trotzdem leer
MfG Flux
- Bearbeitet Flux1989 Montag, 6. August 2012 14:52
-
Weil du deine Form benutzen musst, keine neue Instanz:
this.listBox1.Items.Add(notificationStr);
das "this." kannst du auch weglassen, dient aber der übersichtlichkeit.
In deinem Auskommentierten Codestück hättest du es zu einer ListBox hinzugefügt die in einer anderen Instanz liegt, die aber noch nicht angezeigt wurden ist und somit gabs auch deine listBox1 noch nicht und somit kam die Exception.
Koopakiller - http://koopakiller.ko.ohost.de/
-
das "this." kannst du auch weglassen, dient aber der übersichtlichkeit.
Ohne this zeigt IntelliSense keine listBox1, daher war das der Schlüssel, um die Instanz, welche in Program.cs erzeugt wird ("Application.Run(new Form1());") zu referenzieren.
Danke nochmals!