hi,
meine Form1 die sich um die Grafiken kümmert, lädt auch auf Befehl eine
Textdatei. Diese muss verarbeitete werden. Dazu ist eine 2. Klasse
(test.cs) notwendig die in einem externen cs-file untergebracht ist -
also kein Member von Form1 ist. Wenn ich nun eine Instanz von class test
erzeuge, möchte ich aber auch rückwärts kommunizieren können, sprich
wieder Information zurück an form1 senden, damit diese auf dem
Bildschirm dargestellt werden können!
Wie mache ich sowas am sinnvollsten? Reicht es beim Erzeugen von test
dem Konstruktor eine Referenz von form1 mit zu übergeben, oder gibt es
elegantere Methode?
Bsp:
1
this.test1=newtest(this);
EDIT: Habe soeben hier im Forum eine ähnliche Diskussion gefunden, da
wird meine Methode zwar empfohlen aber später wiederum als "dirty"
bezeichnet.
Daraufhin wurde auf diesen thread hier verwiesen
http://www.mycsharp.de/wbb2/thread.php?threadid=5960
scheint wohl ein beliebtes thema zu sein!
naja danke trotzdem.
Deklariere in der Test Class Events auf die sich die Form anmelden
(eventhandler) kann.
Somit muss Test Class nichts von Form1 wissen und du kannst
Test Class ohne Probleme in einem anderen Projekt auch
wieder verwenden!
Grüße
Christian
Christian R. schrieb:> Deklariere in der Test Class Events auf die sich die Form anmelden> (eventhandler) kann.> Somit muss Test Class nichts von Form1 wissen und du kannst> Test Class ohne Probleme in einem anderen Projekt auch> wieder verwenden!>> Grüße> Christian
öhm kannst du das vll ein wenig konkretisieren? was bedeutet anmelden in
dem kontext?
Ein EventHandler ist für ereignisbasierende Kommunikation.
Beispielsweise bei einer seriellen Schnittstelle, wenn etwas empfangen
wurde, wird das Empfangsereignis ausgelöst. Quasi so eine Art Interrupt.
Eine deiner Klassen stellt also ein Ereignis bereit, mit dem es
ankommende Daten empfangen kann. Die zweite Klasse löst das Ereignis in
der ersten Klasse aus und übergibt die Daten.
Ralf
<c#CrashKurs>
Anbei ein Code-Sample.
WinForm mit 2 Buttons und einer TextBox.
Eine Klasse "Test" die ein event feuern kann.
Button1 -> an das Event anmelden.
Button2 -> Event auslösen.
TextBox wird befüllt wenn Eventhandler aufgerufen wird.
Klasse Test beinhaltet noch eine Klasse für EventArgs. Der quasi
Übergabeparameter des Eventhandlers.
Schau mal drüber und debug dich mal durch - du wirst dich sicher zurecht
finden :)
Sollte das Event von Test aus asynchron zum MainThread gefeuert werden,
muss mit "Invoke" synchronisiert werden. Das erklär ich dir, wenn du's
brauchst, im nächsten Schritt.
</c#CrashKurs>
Habe es jetzt erstmal mittels Referenz gelöst. Die Sache mit dem
EventHandler werde ich mir nochmals genauer anschauen, danke!
Andere Frage: Ist es eigentlich ok, wenn ich alles was mit Grafik, bzw.
meinem user interface zu tun hat, in der Form1 belassen? Oder lagert man
so viel es geht in andere Klassen aus?
Referenzen haben den Nachteil, dass es zu eng verstrickten
Abhängigkeiten
kommt. Eine Klasse, die eine Logik implementiert, die eigentlich nichts
mit Form1 zu tun hat sollte auch nicht damit verwoben werden.
Deswegen das Vorgehen mit Events / Delegates. Du könntest auch
ein Action<...> delegate implementieren. Wenn es nur genau einen
Empfänger für das Ereignis gibt!
Der Ansatz, Logik und UserInterface zu trennen ist genau richtig!!
Man nennt das Muster: MVC Model View Controller oder MVVM Model View
ViewModel.
Zur Frage, was man auslagern soll: Alles auslagern, was man wo anders
vielleicht noch mal verwenden könnte.
"Divide et impera" (http://de.wikipedia.org/wiki/Divide_et_impera)
Teile und herrsche:
Oberflächenanteile, die eine bestimmte Funktionalität beinhlaten - kann
man schön in Controls kapseln. BusinessLogik - eigene Klassen
definieren, interface dazu und in ein eigenes Assembly.
Datenbankzugriffsschicht getrennt implementieren. Auf eine saubere
Trennung kommt es an.
Sicher nicht beim Pimperltool was so in einer halben Stunde
runtergehackt wird.
Aber wenn die Applikation größer zu werden scheint - bitte vorher
Gedanken über die Modelle machen und dann hast du's auch leichter das
Ding zu warten.
Es ist einfach peinlich, die eigene Software nach einem halben Jahr
Enticklungspause nicht mehr zu verstehen.
Viel Glück!
Christian
Christian R. schrieb:> <c#CrashKurs>>> Anbei ein Code-Sample.>> WinForm mit 2 Buttons und einer TextBox.>> Eine Klasse "Test" die ein event feuern kann.>> Button1 -> an das Event anmelden.> Button2 -> Event auslösen.> TextBox wird befüllt wenn Eventhandler aufgerufen wird.>> Klasse Test beinhaltet noch eine Klasse für EventArgs. Der quasi> Übergabeparameter des Eventhandlers.>> Schau mal drüber und debug dich mal durch - du wirst dich sicher zurecht> finden :)>> Sollte das Event von Test aus asynchron zum MainThread gefeuert werden,> muss mit "Invoke" synchronisiert werden. Das erklär ich dir, wenn du's> brauchst, im nächsten Schritt.>> </c#CrashKurs>
Habe das Programm erstmal mit Referenzen gelöst, um zu sehen ob es
läuft. Ich denke aber, dass deine Methode die Bessere ist. Also habe ich
mir den Code mal angeschaut.
Ok, als Voraussetzung für ein event handling muss diese Klasse einen
handler definiert haben?:
1
publiceventEventHandler<MyArgs>MyEvent;
erst dieser macht es möglich auf events zu reagieren?
Dann erzeuge ich eine Instanz mittels Button1, als Parameter die Methode
die Aufgerufen werden soll):
ok, aber der Event auf form 1 ruft ja eine text box die auch auf form1
liegt auf, dafür muss ich ja nicht über die Test-Klasse gehen. Oder
sollte das nur ein Bsp. sein? Denn ich will ja, das etwas in der
Test-Klasse passiert. Also Form1 ruft Test auf und triggert dort ein
Event (berechne x*y). Beim beenden soll Test etwas auf form1 einblenden
zB.: "success". Danach wird wieder gewartet bis der nächste Button auf
form 1 gedrückt wird.
Weisst du was ich meine?
>> Ok, als Voraussetzung für ein event handling muss diese Klasse einen> handler definiert haben?:
Den Handler hat der, der das Event konsumiert. Bei der Testklasse wird
das event implementiert. Das event ist das, was signalisieren kann.
> ok, aber der Event auf form 1 ruft ja eine text box die auch auf form1> liegt auf, dafür muss ich ja nicht über die Test-Klasse gehen. Oder> sollte das nur ein Bsp. sein?
ja, ganz genau. war nur mal auf die Schnell hingehackt - damit du dir
was vorstellen kannst. Natürlich wäre so eine Implementierung nicht
recht
schlau (schon gar nicht, die Klasse TEST zu nennen ;o) ) aber zum Lernen
sollte es passen.
> Denn ich will ja, das etwas in der> Test-Klasse passiert. Also Form1 ruft Test auf und triggert dort ein> Event (berechne x*y). Beim beenden soll Test etwas auf form1 einblenden> zB.: "success". Danach wird wieder gewartet bis der nächste Button auf> form 1 gedrückt wird.>> Weisst du was ich meine?
ja, weiß ich! Deswegen das nächste Beispiel. Ein wenig umgeändert.
Button1 -> Handler mit Event verbinden
Button2 -> Startet eine Berechnung, die ich mit Sleep(...) künstlich in
die Länge gezogen habe.
Ist die Berechnung fertig - wird das event gefeuert.
VORSICHT: da die Berechnung und das feuern des events in einem anderen
Thread abspielt, muss synchronisiert werden, wenn man in diesem auf
controls
in der Form zugreifen möchte!! Das Beispiel zeigt das, wie das mit
Invoke
gemacht werden kann.
Viel Erfolg,
Christian
danke schön soweit, aber irgendwie stellt sich mir da direkt eine Frage,
muss ich denn hier überhaupt threading betreiben? Um die
synchronisierung zu vernachlässigen und wenn ich gleichzeitig festlege,
das keine andere Aktion in dieser Zeit vom user aufgerufen werden kann,
so könnte ich doch strikt sequentiell arbeiten - also single threaded?!!
Oder ist multi threading hier zwangsläufig nötig?
Peterle Anonym schrieb:> danke schön soweit, aber irgendwie stellt sich mir da direkt eine Frage,> muss ich denn hier überhaupt threading betreiben? Um die> synchronisierung zu vernachlässigen und wenn ich gleichzeitig festlege,> das keine andere Aktion in dieser Zeit vom user aufgerufen werden kann,> so könnte ich doch strikt sequentiell arbeiten - also single threaded?!!>> Oder ist multi threading hier zwangsläufig nötig?
Das hängt davon ab ob deine Aktivität länger dauert und ob du das dem
Benutzer zumuten kannst.
Während deine Aktivität (zB Berechnung) läuft und du singel threaded nur
im MainThread arbeitest, steht natürlich deine WinForm.
Wenn das eine halbe Sekunde dauert - dann ist das u.U. auch ok.
Sollte die Aktivität doch länger dauern - dann wird der Benutzer
ungeduldig und beginnt wild herum zu klicken.
Theoretisch kannst du dir den ganzen event & callback Mechanismus im
Fall 1
sparen! Weil du in der Testklasse einfach eine Methode implementierst,
die als return Wert das zurück liefert, was du zum Anzeigen in der Form
brauchst.
1
this.textBox1.Text = new TestClass().DoWas().ToString();
(bitte das ist nu ein schlechtes Beispiel zur Veranschaulichung!!)
Grüße,
Christian
Christian R. schrieb:> Peterle Anonym schrieb:>> danke schön soweit, aber irgendwie stellt sich mir da direkt eine Frage,>> muss ich denn hier überhaupt threading betreiben? Um die>> synchronisierung zu vernachlässigen und wenn ich gleichzeitig festlege,>> das keine andere Aktion in dieser Zeit vom user aufgerufen werden kann,>> so könnte ich doch strikt sequentiell arbeiten - also single threaded?!!>>>> Oder ist multi threading hier zwangsläufig nötig?>> Das hängt davon ab ob deine Aktivität länger dauert und ob du das dem> Benutzer zumuten kannst.> Während deine Aktivität (zB Berechnung) läuft und du singel threaded nur> im MainThread arbeitest, steht natürlich deine WinForm.> Wenn das eine halbe Sekunde dauert - dann ist das u.U. auch ok.> Sollte die Aktivität doch länger dauern - dann wird der Benutzer> ungeduldig und beginnt wild herum zu klicken.>> Theoretisch kannst du dir den ganzen event & callback Mechanismus im> Fall 1> sparen! Weil du in der Testklasse einfach eine Methode implementierst,> die als return Wert das zurück liefert, was du zum Anzeigen in der Form> brauchst.>>
1
this.textBox1.Text = new TestClass().DoWas().ToString();
> (bitte das ist nu ein schlechtes Beispiel zur Veranschaulichung!!)>> Grüße,> Christian
Sagen wir's so, ich bin mir sicher, dass während der Berechnung der User
nicht ungeduldig wird, denn er weiss, dass das Programm nur diese eine
Sache kann!
Somit ist MT nicht nötig in meinem Fall und würde nur zu overhead
seitens des Codes führen.
Somit würde ich die test klasse ohne MT implementieren und auch die
Form1. aber dann tritt das problem auf , das "OnCalcFinished" eine
exception wirfst, wie du es ja beschrieben hast!
EDIT: bei mir wirft es keine exception wenn ich deinen Code ohne MT
implementiere...
Wer triggert die Aktion?
Also wenn du auf eine Button-Click reagierst und die Funktion der
Klasse Test ausführst brauchst du auch kein Event oder einen
Eventhandler dazu!
Werte doch einen Return werd der Funktion aus (siehe Beispiel oben) und
du bist alle Sorgen los!
oder nicht?
Christian R. schrieb:> Wer triggert die Aktion?> Also wenn du auf eine Button-Click reagierst und die Funktion der> Klasse Test ausführst brauchst du auch kein Event oder einen> Eventhandler dazu!> Werte doch einen Return werd der Funktion aus (siehe Beispiel oben) und> du bist alle Sorgen los!>> oder nicht?
Hab mal etwas rumgefummelt und es hinbekommen:
habe in der "Testklasse" einen thread gestartet, der eine queue gefüllt
hat, danach wurde ein event auf form1 ausgelöst welches wiederum einen
delegaten benutzt hat um die queue zu lesen und auf die form zu
schreiben.
Danke nochmal, hast mir sehr geholfen!! Auch dein Beitrag über MVC war
hilfreich!!
gruß
> Dann mach es ST und setz den Cursor auf "Wait"!>> Du hast hier soviel Möglichkeiten aufgezeigt bekommen, langsam wirds> Zeit mal in Buch zu schauen! :>> http://openbook.galileocomputing.de/visual_csharp/...
wat? wer bist du denn?
ist es dann immer noch eine "saubere" Methode? Oder lege ich lieber
einen Zwischen-Event an?
2) Die Queue sollte nicht in der aufgerufenen Klasse, sondern in der
aufrufenden Klasse erzeugt werden, um den Verlust der Daten zu
vermeiden, falls die Klasse de-initialisiert wird oder? Übergebe ich
dann einfach eine Referenz der Queue mit an die erzeugte Klasse?
zu 1. Du meinst du möchtest den EventHandler für eine Funktion in einer
Instanz der Klasse class2 innerhalb einer Instanz der Klasse class1
zuweisen? Und alternativ in der Klasse class1 eine Art Zwischenebene
einbauen? Ist das nicht dann eher ein Umweg?
Welche Variante aus dem Bild hast du denn implementiert?
zu 2. Die Daten gehen erst dann verloren, wenn der Garbage Collector der
Meinung ist, die Daten werde nicht mehr gebraucht.
Hier das Bild. Irgendwie kann man bei Bearbeiten keine Bilder mehr
hochladen.
Also, entweder die linke Variante mit der verschachtelten Klasse oder
die rechte mit zwei unabhängigen Klassen?
Form1->class1->class2->MessageReceived()
Damit würde ich in class2 einen Event in der Form1 auslösen. Und meine
Frage war, ob das so in Ordnung geht?
2) Und wann ist er dieser Meinung, also was genau muss passieren? Hätte
jetzt die Queue in der übergeordneten Klasse erzeugt und nach unten
durchgereicht?!
zu 1. Damit sehe ich kein Problem. Ist Geschmackssache, denk ich.
zu 2. Genau genommen weiß ich das nicht. Allerdings hatte ich noch nie
Probleme damit. Wenn dus genau wissen willst, musst du mal nach Garbage
Collector suchen und dich rein lesen.