Zu Hauptinhalt springen

 none
[WinForms/VB.Net] Popup und DropDown Fenster RRS feed

  • Frage

  • Hallo Leute,

    schon seit Ewigkeiten frage ich mich, wie die Funktionsweise ist aller DropDown-Menüs bei ComboBoxen, Datumwähler, Kontextmenü usw. und der Popup-Fenster, die schnell und sachnah Informationen anbieten können. Deswegen experimentiere ich bereits seit langer Zeit an der Idee, ein solches Ding zu erstellen. Doch egal wie ich es angehe, irgendwelche Probleme verhindern ein stabiles Funktionieren.

    Grundsätzlich gehe ich aus zwei Gründen davon aus, dass solche Dinge Fenster sein müssen:

    1. Reine Steuerelemente werden gar nicht erst angezeigt, solange sie nicht Teil einer ControlCollection sind.
    2. Wenn sie Teil einer solchen sind, werden sie nicht über den Rand ihres Parent gezeichnet.

    Also habe ich eine Klasse, die von Form erbt.

    Das große Problem ist, dass das Ding sich ja ausblenden muss, wenn der Benutzer irgendwo hinklickt, das nicht das Ding oder sein Inhalt ist. Meine Idee ist, dass das Fenster sich ausblendet, wenn es den Fokus verliert und das LostFocus-Ereignis feuert. Da ein Fenster aber standardmäßig keinen Fokus erhalten kann und damit auch keinen verlieren kann, konnte ich nicht einfach über das LostFocus-Ereignis gehen. Nach langem Hin und Her Suchen fand ich zwei Ideen:

    1. Das übergeordnete Fenster fügt an alle Steuerelemente und Untersteuelemente ein Ereignis-Handler, nachdem das Menü auf ein Klick ausgeblendet wird (Stackoverflow).
    2. Ich behandle die Nachrichten an den Windows-Prozess (Stackoverflow).
    3. Das Fenster wird um den Stil WS_POPUP erweitert (Stackoverflow).

    Ersteres ist nicht gangbar, weil

    • es unhandlich ist;
    • das Ausblenden muss ja von sich aus funktionieren, ohne das übergeordnete Steuerelement zusätzlich konfigurieren zu müssen; und
    • logischerweise funktioniert das Ausblenden nicht mit Klicks ganz fernab der Anwendung.

    Zweites hat das Verhalten meines übergeordneten Fensters völlig zerschossen.

    Letzteres hat nichts geändert. Zwar kann das Fenster aktiviert werden, jedoch erhält es ja dadurch noch nicht den Fokus. Daneben wird das übergeordnete Fenster ja auch deaktiviert, was nicht dasselbe, gewünschte Verhalten wäre.

    Inzwischen bin ich mit meinem Latein am Ende. Ich kann das gewünschte Verhalten nicht reproduzieren. Entweder es ist so simpel, dass man das nirgendwo im Internet problematisieren müsste, oder jeder hat die Schwierigkeit, nur ist die Lösung eines der wohlgehütesten Betriebsgeheimnisse der Desktop-OS-Entwicklung.

    Jetzt ist meine große Hoffnung, dass jemand von euch mir auf die Sprünge helfen kann.

    Grüße

    Martin


    Wupp Wupp! Fnak Fnak!


    Samstag, 3. August 2019 19:09

Antworten

  • Hallo Ivan,

    wenn ich Deine Ausführungen bzgl. des Fokus richtig verstehe (korrigiere mich bitte, wenn es doch falsch ist), erhalten alle Elemente (Formulare, Steuerelemente und Menüs) ihren Fokus von ihrem übergeordneten Steuerelement, aber:

    • Formulare übernehmen ihn und teilen ihn mit untergeordneten Elementen.
    • Steuerelemente übernehmen ihn und geben ihn an ihre untergeordneten Elemente weiter.
    • Menüs teilen ihn mit dem übergeordneten Element und teilen ihn mit untergeordneten Elementen.


    Ich habe mich, von Deiner Antwort angestoßen, ein wenig über die ToolStripDropDown-Komponente, die anscheinend die Grundkomponente für mein Anliegen darstellt, informiert und wie man sie verwendet. Dabei war der Beitrag von DonBoitnott hilfreich:

    • Den Inhalt des DropDowns/Menüs verpackt man in ein ToolStripControlHost.
    • Den Host fügt man als Element zu einem ToolStripDropDown hinzu, welches CanOverflow, AutoClose und ggf. DropShadowEnabled auf True gesetzt hat.
    • Um den ToolStripDropDown dann anzuzeigen, berechnet man den Anzeigepunkt und ruft mit diesem die Show()-Methode auf. Das ganze vermutlich in einem Ereignis ausgelöst, z. B. ein Button.Click-Ereignis.
    • Wichtig ist, den ToolStripDropDown nicht zu den Steuerelemente des Formulars hinzuzufügen, da sonst seine Anzeige nicht über den Clientbereich des Formulars reichen kann, also kein Overflow dargestellt würde.

    Im Fazit war die Lösung also doch so einfach, dass sie jedem klar war außer mir. Warum ich bei meiner ewigen Suche nicht auf diese Komponente gestoßen bin, ist mir ein Rätsel. Jetzt frage ich mich, ob die Komponente in dem Fall als Menü nur ein Workaround ist oder sozusagen auch "offiziell" dafür gedacht ist?

    Auf jeden Fall vielen Dank für den Denkanstoß. Damit kann ich endlich viele meiner Ideen korrekt und stabil umsetzen, ohne mir frustrierende Workarounds ausplanen zu müssen.

    Grüße,

    Martin


    Wupp Wupp! Fnak Fnak!

    Mittwoch, 7. August 2019 11:19

Alle Antworten

  • Hallo Martin,

    Es kann der folgende Vergleich zwischen Elementen basierend auf dem Fokus gemacht werden:
    • Formulare erhalten den Fokus von Ihrem übergeordneten Element, aber sie haben auch eine separate Konzeption des Fokus für Ihre Steuerelemente.
    • Steuerelemente nehmen Fokus von ihrem übergeordneten Element, aber sie übergeben ihn an ihren untergeordneten Elemente.
    • Menüs teilen den Fokus mit ihren übergeordneten und untergeordneten Elementen.
    Du kannst versuchen, den ComboTreeBox-Controller zu verwenden, der ein Beispiel für ein benutzerdefiniertes Dropdown-Menü darstellt und auch eine Lösung für das Problem beim Erstellen dieses Menüs in Windows Forms bietet. Die ToolStripDropDown-Komponente macht dies alles möglich, obwohl Du (in diesem Fall) den Inhalt des Dropdown-Menüs manuell implementieren müsstest. Weitere Informationen findest Du in diesem Artikel:
    A ComboBox with a TreeView Drop-Down

    Gruß,

    Ivan Dragov


    Bitte haben Sie Verständnis dafür, dass im Rahmen dieses Forums, welches auf dem Community-Prinzip „IT-Pros helfen IT-Pros“ beruht, kein technischer Support geleistet werden kann oder sonst welche garantierten Maßnahmen seitens Microsoft zugesichert werden können.


    Dienstag, 6. August 2019 11:25
    Moderator
  • Hallo Ivan,

    wenn ich Deine Ausführungen bzgl. des Fokus richtig verstehe (korrigiere mich bitte, wenn es doch falsch ist), erhalten alle Elemente (Formulare, Steuerelemente und Menüs) ihren Fokus von ihrem übergeordneten Steuerelement, aber:

    • Formulare übernehmen ihn und teilen ihn mit untergeordneten Elementen.
    • Steuerelemente übernehmen ihn und geben ihn an ihre untergeordneten Elemente weiter.
    • Menüs teilen ihn mit dem übergeordneten Element und teilen ihn mit untergeordneten Elementen.


    Ich habe mich, von Deiner Antwort angestoßen, ein wenig über die ToolStripDropDown-Komponente, die anscheinend die Grundkomponente für mein Anliegen darstellt, informiert und wie man sie verwendet. Dabei war der Beitrag von DonBoitnott hilfreich:

    • Den Inhalt des DropDowns/Menüs verpackt man in ein ToolStripControlHost.
    • Den Host fügt man als Element zu einem ToolStripDropDown hinzu, welches CanOverflow, AutoClose und ggf. DropShadowEnabled auf True gesetzt hat.
    • Um den ToolStripDropDown dann anzuzeigen, berechnet man den Anzeigepunkt und ruft mit diesem die Show()-Methode auf. Das ganze vermutlich in einem Ereignis ausgelöst, z. B. ein Button.Click-Ereignis.
    • Wichtig ist, den ToolStripDropDown nicht zu den Steuerelemente des Formulars hinzuzufügen, da sonst seine Anzeige nicht über den Clientbereich des Formulars reichen kann, also kein Overflow dargestellt würde.

    Im Fazit war die Lösung also doch so einfach, dass sie jedem klar war außer mir. Warum ich bei meiner ewigen Suche nicht auf diese Komponente gestoßen bin, ist mir ein Rätsel. Jetzt frage ich mich, ob die Komponente in dem Fall als Menü nur ein Workaround ist oder sozusagen auch "offiziell" dafür gedacht ist?

    Auf jeden Fall vielen Dank für den Denkanstoß. Damit kann ich endlich viele meiner Ideen korrekt und stabil umsetzen, ohne mir frustrierende Workarounds ausplanen zu müssen.

    Grüße,

    Martin


    Wupp Wupp! Fnak Fnak!

    Mittwoch, 7. August 2019 11:19