PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C# .NET, Delegates und Events


Gohan
2009-09-09, 18:49:24
Hi, verzweifele gerade an einer eigentlich nicht so schweren Aufgabe, bei der es sich um Delegates und Events dreht. Folgende Aufgabe ist gegeben:

Erstelle eine Windows-Forms Applikation mit einer TextBox auf einem Formular. Das Formular soll zwei Events besitzen. PassphraseEntered (wird ausgelöst, sobald die TextBox den Inhalt „Mustertext“ enthält) und TextChanged (wird immer ausgelöst, wenn sich der Inhalt der TextBox ändert). Wie kann das TextChanged Event der TextBox weitergeleitet werden, ohne einen neuen Delegate zu definieren?

Irgendwie sehe ich mittlerweile den Wald vor lauter Bäumen nicht mehr und komm einfach nicht weiter. Meine Lösung sieht derzeit wie folgt aus, aber ist meines Erachtens nach völlig am Thema vorbei geschrieben (zur Info, ich weiß das ich object sender und EventArgs bei meiner Ausfürhung auch weglassen könnte, habe sie aber mal drin gelassen, vielleicht lässt sich ja noch was retten :) ):

namespace EventsAndDelegates
{
public delegate void PassphraseEnteredHandler(object sender, EventArgs e);

public partial class Form1 : Form
{
public event PassphraseEnteredHandler passphraseEntered;
public event PassphraseEnteredHandler textChanged;

public Form1()
{
InitializeComponent();
passphraseEntered += new PassphraseEnteredHandler(passwortGefunden);
textChanged += new PassphraseEnteredHandler(buchstabeGetippt);

}

private void passwortGefunden(object sender, EventArgs e)
{
MessageBox.Show("Sie haben das Passwort gefunden!");
}

private void buchstabeGetippt(object sender, EventArgs e)
{
MessageBox.Show("Eingabe getätigt.");
}

private void textBox1_TextChanged(object sender, EventArgs e)
{
if (textBox1.Text == "Mustertext")
{
if (passphraseEntered != null)
{
passphraseEntered(sender, e);
}
}
else
{
if (textChanged != null)
{
textChanged(sender, e);
}
}
}
}
}

Die Form besteht einfach aus einem Formular mit einem Textfeld. Wie würdet ihr die gestellte Aufgabe lösen?

Monger
2009-09-09, 20:58:13
Hab grad nicht so viel Zeit zum antworten... schaue es mir morgen nochmal genauer an.

Aber: zumindest das TextChanged Event kommt ja direkt von Textbox. Schließlich kann auch nur die Textbox das Event raisen. Alles was du tun musst, ist den Handler direkt an der Textbox zu registrieren. Nur die Handling Methode sitzt dann in der Form (so sieht das dann übrigens auch typischerweise im Visual Studio aus, wenn der Designer die Event Handler anlegt).

Deshalb peile ich nicht so ganz, warum hier zwei Events gefordert sind. Meiner Meinung nach macht nur das eine, selbstdefinierte hier Sinn.

Und das "Passphrase Entered" Event wird halt ausgelöst, sobald im "TextChanged" Event eine gewisse Überprüfung erfolgreich ist.

Btw. : du brauchst keinen eigenen Delegate deklarieren. Nimm doch einfach das ActionEvent was die Textbox (und viele andere Controls) auch nutzt.

xxxgamerxxx
2009-09-09, 21:22:51
Die Frage zielt meines Erachtens auf das Nichterstellen eines Delegaten ab. Das ist sowieso nicht notwendig, weil TextChanged eine Instanz vom Standard Delegaten ist. Ich würde es so machen:


public partial class Form1 : Form
{
public event EventHandler PassphraseEntered;
public new event EventHandler TextChanged;

public Form1()
{
InitializeComponent();
}

private void TextBoxPassword_TextChanged(object sender, EventArgs e)
{
if (TextChanged != null)
TextChanged(sender, e);

if (PassphraseEntered != null && this.textBoxPassword.Text == "Mustertext")
PassphraseEntered(sender, e);
}
}


Beim PassphraseEntered event habe ich jetzt einfach auch mal den Standard Delegaten genommen, das ging ja nicht genauer aus der Frage hervor.

xxxgamerxxx
2009-09-09, 21:28:45
Deshalb peile ich nicht so ganz, warum hier zwei Events gefordert sind. Meiner Meinung nach macht nur das eine, selbstdefinierte hier Sinn.


Weil du sonst die TextBox public bzw. internal machen müsstest. Und dann könnten die Aufrufer der Form einfach auf die TextBox zugreifen und irgendwelche Werte reinschreiben (oder gar automatisiert damit gezielt auf Passwörter prüfen). Vom Sicherheitsaspekt und OO Gedanke eher suboptimal.

xxxgamerxxx
2009-09-09, 21:47:16
Mir ist gerade aufgefallen, dass ja alle Controls eine Text Eigenschaft bzw. ein TextChanged event haben. Allerdings wird das bei der Form für den Titel in der Form verwendet. Du könntest jetzt noch folgendes machen, wenn du ganz faul bist:


public partial class Form1 : Form
{
public event EventHandler PassphraseEntered;

public Form1()
{
InitializeComponent();
}

private void TextBoxPassword_TextChanged(object sender, EventArgs e)
{
this.Text = this.textBoxPassword.Text;

if (PassphraseEntered != null && this.textBoxPassword.Text == "Mustertext")
PassphraseEntered(sender, e);
}
}


Allerdings siehst du dann im Titel der Form, was du in die TextBox gerade eintrippst. Klingt auch nicht gerade, ob das gewollt/sinnvoll wäre :biggrin:
Ich würde deshalb dann lieber wie oben ein eigenes TextChanged event deklarieren.

Monger
2009-09-09, 22:20:46
Weil du sonst die TextBox public bzw. internal machen müsstest. Und dann könnten die Aufrufer der Form einfach auf die TextBox zugreifen und irgendwelche Werte reinschreiben (oder gar automatisiert damit gezielt auf Passwörter prüfen). Vom Sicherheitsaspekt und OO Gedanke eher suboptimal.
Hmm???

Die Events von TextBox sind alle Public. Macht ja sonst auch keinen Sinn. Die Textbox an sich kannst du aber natürlich private oder sonstwas machen, damit nur die Form selber diese verwaltet. Der Event Handler muss dann aber selbstverständlich sich ebenfalls in der Form befinden.


public partial class Form1 : Form
{

public Form1()
{
InitializeComponent();
// Die nächste Zeile steht üblicherweise im InitializeComponent
this.textBoxPassword.TextChanged += new EventHandler(TextBoxPassword_TextChanged);
}

private void TextBoxPassword_TextChanged(object sender, EventArgs e)
{

}

}

Gast
2009-09-09, 22:36:02
Hmm???

Die Events von TextBox sind alle Public. Macht ja sonst auch keinen Sinn.



Die Textbox an sich kannst du aber natürlich private oder sonstwas machen, damit nur die Form selber diese verwaltet. Der Event Handler muss dann aber selbstverständlich sich ebenfalls in der Form befinden.


public partial class Form1 : Form
{

public Form1()
{
InitializeComponent();
// Die nächste Zeile steht üblicherweise im InitializeComponent
this.textBoxPassword.TextChanged += new EventHandler(TextBoxPassword_TextChanged);
}

private void TextBoxPassword_TextChanged(object sender, EventArgs e)
{

}

}



Ziel ist ja laut Frage, dass die Form selbst events besitzt, damit der Aufrufer dieser Form informiert wird. Also in der Art:

FormPassword frmPswd = new FormPassword()
frm.TextChanged += ...
frm.PassphraseEntered +=...
frm.Show();

Deine Aussage war nun:


Alles was du tun musst, ist den Handler direkt an der Textbox zu registrieren.


Daraus habe ich folgendes in der Art gefolgert:

FormPassword frmPswd = new FormPassword()
frm.meineTextBox.TextChanged += ...

Monger
2009-09-09, 23:40:43
Jetzt bin ich endgültig verwirrt. Der Sinn eines Event Attributs ist doch, andere Teilnehmer über Events zu informieren, und nicht etwa selbst informiert zu werden. Was bringt es der Form ein Event "TextChanged" zu haben, wenn sie dieses nicht selbst auslösen kann? Die Information, wann Text in der Textbox geändert wurde, kennt nunmal einzig und allein die Textbox.

Was du natürlich machen kannst, ist: sich am TextChanged Event von der TextBox registrieren, und in Folge dessen ein "TextChanged" Event im TextChanged Handler in der Form auslösen. Vielleicht ist das ja des Rätsels Lösung.

xxxgamerxxx
2009-09-09, 23:57:44
Jetzt bin ich endgültig verwirrt. Der Sinn eines Event Attributs ist doch, andere Teilnehmer über Events zu informieren, und nicht etwa selbst informiert zu werden.


Hast du vielleicht schon mal daran gedacht, dass die Form von irgendwo instanziert und verwendet werden kann? Es ist ja durchaus möglich, dass man eine generische Passwort Form hat und dann in der Haupt Form (die die Passwort Form instanziert) einfach das entsprechende Ereignis behandelt, wenn die Authentifizierung erfolgreich war.

Außerdem steht es ja auch mehr als deutlich in der Aufgabenstellung:


Das Formular soll zwei Events besitzen. PassphraseEntered (wird ausgelöst, sobald die TextBox den Inhalt „Mustertext“ enthält) und TextChanged (wird immer ausgelöst, wenn sich der Inhalt der TextBox ändert).




Was bringt es der Form ein Event "TextChanged" zu haben, wenn sie dieses nicht selbst auslösen kann? Die Information, wann Text in der Textbox geändert wurde, kennt nunmal einzig und allein die Textbox.


Natürlich gar nichts, wenn du das TextBox Event nicht weiterleitest. Und genau so steht es ja auch in der Aufgabenstellung:


Wie kann das TextChanged Event der TextBox weitergeleitet werden, ohne einen neuen Delegate zu definieren?




Was du natürlich machen kannst, ist: sich am TextChanged Event von der TextBox registrieren, und in Folge dessen ein "TextChanged" Event im TextChanged Handler in der Form auslösen. Vielleicht ist das ja des Rätsels Lösung.

Genau das habe ich auch in meinem obigen Code gemacht. Die Handlerverknüpfung steht halt in der Designer.cs, aber das ist ja wohl klar.

Expandable
2009-09-10, 09:28:47
Noch eine Idee (folgender Code gehört in die Form-Klasse, Annahme, die TextBox heißt textbox und TextChanged ist vom Typ System.EventHandler):


public event EventHandler TextChanged
{
add { this.textbox.TextChanged += value; }
remove { this.textbox.TextChanged -= value; }
}

xxxgamerxxx
2009-09-10, 20:50:15
Noch eine Idee (folgender Code gehört in die Form-Klasse, Annahme, die TextBox heißt textbox und TextChanged ist vom Typ System.EventHandler):


public event EventHandler TextChanged
{
add { this.textbox.TextChanged += value; }
remove { this.textbox.TextChanged -= value; }
}


Um das TextChanged Ereignis weiterzureichen ist das eine echt coole Idee, an so etwas habe ich gar nicht gedacht.

PatkIllA
2009-09-10, 20:58:03
kollidiert das erneute Deklarieren eines TextChanged EventHandlers nicht mit dem gleichnamigen Event in der Control-Klasse? Müsste doch eine Warnung geben, wenn man es nicht mit explizit new angibt.

xxxgamerxxx
2009-09-10, 21:30:28
Da gibt's nur eine Warnung. Es geht aber trotzdem, das vererbte TextChanged Event wird dabei ausgeblendet.

PatkIllA
2009-09-10, 21:32:25
Warnung könnte ja Punktabzug geben und welches Event man erhält hängt dann doch auch vom Typ der Variable ab.
Man könnte ja auch das schon vorhandene TextChanged event auslösen.
Rein technisch würde ich das auch gar nicht im Form abhandeln.

Meiner Ansicht nach solltest du von TextBox erben, OnTextChanged überschreiben und da dann auf "Mustertext" überprüfen. Das TextChanged Event bleibt dann erhalten. Die Aufgabe sagt ja auch nur, dass du eine WindowsForms-Anwendung schreiben sollst, aber nicht dass das Verhalten im Form gemacht werden kann. Außerdem wird dadurch das Verhalten der Formklasse maßgeblich geändert, was grundlegende OOD-Prinzipien verstößt.
Zum Wiederverwenden von designeten Controls baut eh besser ein Usercontrol. Das kann man dann auch neben anderen Controls in einem beliebigen Fenster benutzen.

Ich wusste auch gar nicht, dass man beim registrieren und deregistrieren auch eigenen Code ausführen kann.

Monger
2009-09-11, 09:27:46
Meiner Ansicht nach solltest du von TextBox erben, OnTextChanged überschreiben und da dann auf "Mustertext" überprüfen.

Dann tut das "TextChanged" Event aber nicht mehr das was man von "Text changed" eigentlich erwarten könnte.
Diese Form der Event-Vergewaltigung finde ich wesentlich schlimmer als meinetwegen der Form ein zusätzliches Event zu verschaffen und das TextBox Event sauber weiterzurouten.

PatkIllA
2009-09-11, 09:31:12
Dann tut das "TextChanged" Event aber nicht mehr das was man von "Text changed" eigentlich erwarten könnte.
Diese Form der Event-Vergewaltigung finde ich wesentlich schlimmer als meinetwegen der Form ein zusätzliches Event zu verschaffen und das TextBox Event sauber weiterzurouten.
TextChanged tut genau das gleiche wie vorher. Ich hielt es jetzt für selbstverständlich das base.OnTextChanged weiterhin aufgerufen wird.

SentinelBorg
2009-09-11, 12:22:45
Die Aufgabenstellung ist murks. Da war sich wohl der Autor nicht im klaren, dass eine Form bereits ein TextChanged-Event besitzt. Da das Überschreiben des Events eine ganz schlechte Idee wäre, weil der Abnehmer normal mit etwas anderem rechnet, würde ich das Event einfach anders nennen, z.B. PasswordInputChanged (keine Angst vor langen Namen, wird sind nicht mehr in den 80ern). Dann im Handler für Textbox.TextChanged in der Bedingung das eine oder das andere Event auslösen und fertig.

Gohan
2009-09-11, 18:56:08
Also erst einmal danke für den vielen Input, letztendlich war dann doch die erste Lösung von xxxgamerxxx die richtige! Wobei ich die anderen Ansätze auch höchst interessant finde.

PatkIllA
2009-09-11, 18:58:32
Also erst einmal danke für den vielen Input, letztendlich war dann doch die erste Lösung von xxxgamerxxx die richtige! Wobei ich die anderen Ansätze auch höchst interessant finde.
Habt ihr das mit dem TextChanged Event vom Form denn noch durchgesprochen. Für mich klingt die Aufgabe nämlich auch so, dass der Ersteller die Aufgabe nicht durchdacht hat.

Gohan
2009-09-11, 20:04:19
Habt ihr das mit dem TextChanged Event vom Form denn noch durchgesprochen. Für mich klingt die Aufgabe nämlich auch so, dass der Ersteller die Aufgabe nicht durchdacht hat.

Das sollte einfach nur zur Prüfung dienen, ob ich weiß das es schon ein TextChanged Event gibt.