Laden...

Funktion (KeyDown) wird doppelt ausgeführt

Erstellt von ChrisProg vor 7 Jahren Letzter Beitrag vor 7 Jahren 4.389 Views
ChrisProg Themenstarter:in
174 Beiträge seit 2009
vor 7 Jahren
Funktion (KeyDown) wird doppelt ausgeführt

Hallo zusammen,

ich habe eine Form, mit einer Pageframe und mehreren Textboxen.

Das Event KeyDown bei allen objekten mit der folgenden Methode verknüpft:


        private void Feld_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                SendKeys.Send("{TAB}");
            }
            if (e.KeyCode == Keys.Escape && !aenderungsmodus)
            {
                Close();
            }
        }


Wenn ich nun in einer Textbox "{Enter}" drücke wird diese Funktion zweimal(!) durchlaufen, einmal für die Pageframe(?) und einmal für die Texbox, die den Focus hat... 🤔

Kann mir jemand erklären, warum das so ist ? (Die Pageframe hat ja nicht den Focus; und die Form macht das nicht ...)

Im Moment habe ich mir geholfen, in dem ich das KeyPress-Event der Pageframe zurückgesetzt habe, aber das kann ja eigentlich nicht die Lösung sein, zumal die Pageframe ja auf Keys.Escape reagieren soll !

MfG Christian

A
764 Beiträge seit 2007
vor 7 Jahren

Hallo ChrisProg,

mal ins Blaue geraten:
KeyEventArgs.Handled

Gruß, Alf

ChrisProg Themenstarter:in
174 Beiträge seit 2009
vor 7 Jahren

Hallo Alf,

OK, das löst das Problem, erklärt aber immer noch nicht, warum eine Pageframe, die nicht den Fokus hat, auf das KeyDown einer Textbox reagiert, und das auch noch **vor **der Textbox ...

Trotzdem Danke für den Tip (kannte ich noch nicht ...)

MfG Christian

A
764 Beiträge seit 2007
vor 7 Jahren

Ich kann es dir auch nicht genau sagen. Probier dochmal so etwas:


        private void Feld_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                //SendKeys.Send("{TAB}");
               [Debug.WriteLine(sender.ToString());]
            }
        }

Vielleicht gibt das etwas Klarheit.

ChrisProg Themenstarter:in
174 Beiträge seit 2009
vor 7 Jahren

Debug gibt leider nicht viel neues her:

Fehlermeldung:
System.Windows.Forms.TabControl, TabPages.Count: 6, TabPages[0]: TabPage: {Kuh}
System.Windows.Forms.MaskedTextBox, Text: 276 05 366 96090
Eine Ausnahme (erste Chance) des Typs "System.ArgumentOutOfRangeException" ist in mscorlib.dll aufgetreten.
Eine Ausnahme (erste Chance) des Typs "System.ArgumentOutOfRangeException" ist in mscorlib.dll aufgetreten.

Wie gesagt die Pageframe feuert noch vor der TextBox ...

Was dieses "ArgumentOutOfRangeException" in diesem Zusammenhang bedeutet - k.A.

Ich habe das ja mit "e.Handled = true" lösen können, nur verstehen würde ich das jetzt auch noch gerne ...

MfG Christian

A
764 Beiträge seit 2007
vor 7 Jahren

Anscheinend wird das KeyDown Event auch von einem TabControl verarbeitet. Wie bindest du denn das Event Feld_KeyDown an die Methode?

Ich kann dein Problem übrigens nicht nachstellen.

Vielleicht hilft auch [Tutorial] Vertrackte Fehler durch Vergleich von echtem Projekt mit minimalem Testprojekt finden

ChrisProg Themenstarter:in
174 Beiträge seit 2009
vor 7 Jahren

In der Ansicht unter der entsprechenden Eigenschaft im DropDown auswählen - also nichts besonderes ...

Sei´s drum, danke für deinen Input 🙂

MfG Christian

1.040 Beiträge seit 2007
vor 7 Jahren

Du hast für das TabControl also auch das KeyDown-Event abonniert?

ChrisProg Themenstarter:in
174 Beiträge seit 2009
vor 7 Jahren

Ja, einfach aus dem Grund heraus, das wenn doch mal der Fokus auf dem TabControl liegen sollte, soll es ebenfalls auf {ESC}-Taste reagieren ...

MfG Christian

463 Beiträge seit 2009
vor 7 Jahren

Ja dann ist doch klar, dass er 2* aufgerufen wird.

ChrisProg Themenstarter:in
174 Beiträge seit 2009
vor 7 Jahren

Erklär mal bitte, denn ich für mich ist es das nicht, da definitiv die TextBox den Fokus hat - u. somit das TabControl nicht den Fokus haben kann, oder ?

(geht das unter .NET doch ? - bei VFP war das jedenfalls ausgeschlossen !)

MfG Christian

1.040 Beiträge seit 2007
vor 7 Jahren

Meiner Erinnerung nach ist die Aussage von Stefan.Haegele korrekt, auch wenn ich es gerade nicht erklären kann und auch gerade dazu keinen passenden Artikel im WWW finde. 😁

Stefan, erleuchte uns. 😉

3.003 Beiträge seit 2006
vor 7 Jahren

Die Antwort ist ein F12 * weit weg.


  protected override void OnKeyDown(KeyEventArgs e)
        {
            TabItem nextTabItem = null;
 
            // Handle [Ctrl][Shift]Tab, Home and End cases
            // We have special handling here because if focus is inside the TabItem content we cannot
            // cycle through TabItem because the content is not part of the TabItem visual tree

LaTino

EDIT: besseren Kommentar aus den Originalquellen zitiert 😃

  • na gut, nur, wenn man jump to referencesource auf F12 hat 😉 Ich will damit sagen: wenn sich ein Control seltsam verhält, und das auch in einem Minimalprojekt, dann schaut bitte in die Quellen.

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

1.040 Beiträge seit 2007
vor 7 Jahren

Ähm, äh, ja. 🤔

Mal davon ab, dass ich persönlich das Verhalten nicht auf das TabControl geschoben hätte,
ist mir auch nicht ganz klar, wie sich das Überschreiben der OnKeyDown-Methode jetzt in das beschriebene Verhalten einfügt.

Es wird ja nur das OnKeyDown des TabControl überschrieben, was allerdings auch nicht aufgerufen werden dürfte - oder irre ich da?
Warum läuft er da rein? 🤔

3.003 Beiträge seit 2006
vor 7 Jahren

Meh. Mein Fehler, hier ist der korrekte Link (bin beim raussuchen beim WPF-Tabcontrol gelandet).

https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/TabControl.cs,cf84486a6d2fb06c

Schau dir den Ablauf beim KeyDown mal genauer an, dann, denke ich, wird klar wo ich die Schuld sehe.

EDIOT: und natürlich wird bei jedem Control OnKeyDown aufgerufen, wenn das KeyDown-Ereignis feuert, bzw um das Ereignis überhaupt zu feuern. Schau dir Control.OnKeyDown an, und da besonders, wo es benutzt wird (Methode ProcessKeyEventArgs in Control.cs).

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

ChrisProg Themenstarter:in
174 Beiträge seit 2009
vor 7 Jahren

Hallo LaTino,

danke für die Info´s ...

Dank deinem Hinweis "jump to reference source" konnte Tante "Google" hierfür die Seite MS Reference Source ermitteln, auf der ich dann auch OnKeyDown finden konnte ...

Und diese Seite kann man in VS für jedes Control individuell aufrufen oder nur gesamt und dann suchen, oder gibt es gar eine Offline-Version davon ???

Gibt es eigentlich eine Möglichkeit in VS in den Eigenschaften direkt anzuzeigen, das da Methoden sind, die aus der Klasse kommen ??? (auch wenn VFP leider tot ist, aber so etwas war unter Eigenschaften sofort zu sehen...)

Aber ich verstehe immer noch nicht, warum das für das TabControl ausgeführt wird, wo doch die TextBox den Fokus hat ...

MfG Christian

3.003 Beiträge seit 2006
vor 7 Jahren

Kurzfassung: Alle von Control abgeleiteten Klassen rufen, wenn eine Taste gedrückt wird, irgendwann ihre überschreibbare Methode OnKeyDown() ab, um das Event auszulösen. TabControl überschreibt diese Methode, um das Tabben zwischen einzelnen Pages zu gestatten. Das funkt dir rein.

LaTino
EDIT: achso, ja, die Frage wegen ref source...mein VS springt bei F12 zur Quelle, und wenn die Quelle nicht von mir/im svn ist, versucht er sie zu finden, oder sucht die refsource und lädt sie (einmalig) herunter, oder dekompiliert das Ganze. Ehrlich gesagt weiß ich nicht einmal, wo das Feature herkommt, ich habe Resharper im Verdacht. Herunterladen kannst du das Ganze auch hier: https://referencesource.microsoft.com/download.html

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

ChrisProg Themenstarter:in
174 Beiträge seit 2009
vor 7 Jahren

Also das heißt dann im Klartext, das so ziemlich jedes Objekt auf einer Form das OnKeyDown-Ereignis auslöst, unabhängig, ob es den Fokus hat, oder nicht 🤔 - welcher Sinn steckt dahinter ?

MfG Christian

1.040 Beiträge seit 2007
vor 7 Jahren

Das mag ja sein, dass das TabControl OnKeyDown() überschreibt, aber mir erschließt sich das Verhalten immer noch nicht.

Der Code der da drin steckt, wird ja nie erreicht, es sollte nur das base.OnKeyDown() aufgerufen werden, also warum ist das Verhalten anders, als wenn es nicht überschrieben worden wäre?

Für das Fenster z.B. läuft er in das OnKeyDown ja auch nicht rein.

3.003 Beiträge seit 2006
vor 7 Jahren

p!lle, watt? 😄

Also, Versuchsaufbau. Leeres WinForms. Panel reinhauen. Dort ein TapControl mit zwei Pages reinhauen, auf die erste TabPage eine TextBox.

Im CodeBehind den hier:


public SimpleBoundForm()
{
    InitializeComponent();

    textBox1.KeyDown += OnKeyDown;
    panel1.KeyDown += OnKeyDown;
    tabControl1.KeyDown += OnKeyDown;
    tabPage1.KeyDown += OnKeyDown;
    tabPage2.KeyDown += OnKeyDown;
    KeyDown += OnKeyDown;
}

private void OnKeyDown(object sender, KeyEventArgs keyEventArgs)
{
    Debug.WriteLine($"{((Control)sender).Name}, keydown.");
}

Starten, Textbox fokussieren, Taste drücken: tabControl1 und textBox1 melden sich.
Offensichtlich, feuert das TabControl mit Hilfe des von Control geerbten OnKeyDown() das KeyDown-Ereignis für sich (also tabControl1.KeyDown) ab. Das bedeutet, dass offenbar vom TabControl irgendwo IM UNTERSCHIED ZU CONTROL die Methode aufgerufen wird, die OnKeyDown() wiederum aufruft, und damit das Event auslöst. Soweit klar?

Jetzt schaut a) in die Methode rein, die OnKeyDown() in Control.cs aufruft (ProcessKeyEventArgs)
Jetzt schaut b) nach TabControl.cs, ob es dort einen Aufruf von ProcessKeyEventArgs gibt, den es in Control() nicht gibt. Tipp: der Aufruf existiert, und er erklärt sogar, wieso das TabControl IMMER das event zuerst kriegt.

Aber das ist eigentlich unnötig. Wichtig ist, zu verstehen, dass TabControl dieses Verhalten hat, und zwar, damit es auf KeyDown-Ereignisse von Controls reagieren kann, die sich nicht standardmäßig unterhalb seiner Containerstruktur befinden, und zwar, BEVOR diese Controls reagieren können.

Aus meiner Sicht hat man das TabControl etwas verkackt und dann auf diese Weise repariert, aber was weiß ich schon.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

1.040 Beiträge seit 2007
vor 7 Jahren

Dann ist doch aber nicht das Überschreiben der OnKeyDown-Methode Schuld, sondern die Tatsache, dass das OnKeyDown (über ProcessKeyEventArgs) im TabControl zusätzlich aufgerufen wird. 😁

Wobei wohl nur mein Kopf der überschriebenen Methode die Schuld gegeben hat, du hast das ja so nie gesagt.

Egal, nun ist es zumindest logisch. =)

3.003 Beiträge seit 2006
vor 7 Jahren

Ich hatte es selbst auch erst so verstanden, bzw nur halb verstanden. Das Verhalten ist (bei uns zumindest) bekannt, es existiert im svn sogar ein workaround, d.h. irgendwer hatte den Erkenntnismoment schon einmal. Daher war ich sicher, dass es am TabControl liegt, nur nicht genau, wo dort.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)