Laden...

Welche Event für "Neben das aktuelle Control klicken" nehmen?

Erstellt von dN!3L vor 12 Jahren Letzter Beitrag vor 12 Jahren 2.132 Views
dN!3L Themenstarter:in
2.891 Beiträge seit 2004
vor 12 Jahren
Welche Event für "Neben das aktuelle Control klicken" nehmen?

Hallo zusammen,

irgendwie stehe ich gerade auf dem Schlauch...
Ich suche ein Event, mit dem ein (fokussiertes/aktiviertes) Control darauf reagieren kann, dass irgendwo anders, nur nicht auf das Control selbst, geklickt wurde.

Konkret möchte ich das Verhalten erreichen, dass z.B. eine ausgeklappte ComboBox oder ein geöffnetes (Kontext-)Menü zeigt: Sobald man irgendwo anders klickt, wird die ComboBox in den ungeöffneten Zustand versetzt bzw. das Kontextmenü verschwindet wieder.

Events wie LostFocus oder Leave werden leider nur ausgelöst, wenn irgendein anderes Control den Focus erhält - was z.B. nicht der Fall ist, wenn man auf ein Label oder einfach auf einen leeren Bereich klickt.

Hat jemand eine Idee, man das bewerkstelligen kann?

5.658 Beiträge seit 2006
vor 12 Jahren

Vielleicht kannst du das Click-Event des (oder der) Parent-Controls abonnieren? Man muß dann halt auch darüber benachrichtigt werden, wenn sich das Parent ändert.

Weeks of programming can save you hours of planning

dN!3L Themenstarter:in
2.891 Beiträge seit 2004
vor 12 Jahren

Nur das Parent (und dessen Parents) überwachen reicht leider nicht. Denn das Click-Event des Parents wird ja nicht ausgelöst, wenn man auf ein (anderes) Child-Control des Parents klickt.
Mit diesem Vorgehen müsste man ja blöderweise alle Controls, die es im aktuellen Fenster gibt, überwachen... 😕

P
157 Beiträge seit 2010
vor 12 Jahren

Dass MouseDown ereignis müsste hilft. Hinzu kommt noch das LeaveFocus ereignis wenn auf ein anderes Steuerelement gedrückt wird. Einziges Problem sid nicht selektierbare Steuerelement,

dN!3L Themenstarter:in
2.891 Beiträge seit 2004
vor 12 Jahren

Dass mouse down erenis hilft

Hm, das wird auch nicht ausgelöst, wenn man auf ein ChildControl klickt.

5.658 Beiträge seit 2006
vor 12 Jahren

Hm, aber irgendwie muß es die ComboBox auch hinbekommen. Vielleicht gibt es ja ein globalen "Mouse-Hook" oder eine Message oder wie sowas hieß, bevor es .NET gab?

Ich weiß nicht ob's helfen könnte, aber schau mal hier: http://www.codeproject.com/KB/cs/globalhook.aspx

Weeks of programming can save you hours of planning

P
157 Beiträge seit 2010
vor 12 Jahren

Die comboBox arbeitet irgend wie mit einem zweiten fenster, einem (ChildWindow).
Diese nachricht wird ausgelößt nachdem eine Combobox geschlossen wird.
WM_PARENTNOTIFY Message

3.170 Beiträge seit 2006
vor 12 Jahren

Hallo,

vielleicht bekommst Du's mit dem Holzhammer raus, indem Du WndProc überschreibst.
Die Childcontrols informieren das Parent-Control über WM_PARENTNOTIFY (0x210) Bei einem MouseDown steht dann im wParam der Wert 0x201 (WM_LBUTTONDOWN), über den lParam bekommst Du auch die Mauskoordinaten.
Die Clicks in den freien Bereich der Form bekommst Du ja einfach über das Click-Event. Wobei Du das dann auch zentral in der WndProc mitbehandeln könntest.

Siehe auch WM_PARENTNOTIFY

Gruß, MarsStein

Edit: PPK war schneller - der Link ist der gleiche 😃

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

I
8 Beiträge seit 2011
vor 12 Jahren

Moin dN!3L,

ich habe bei mir das Problem mit einem MessageFilter gelöst. Hier mal ein Klassenrumpf zur Verdeutlichung:



public class MyMessageObserver : IMessageFilter, IDisposable
{
  private Control myControl;

  public MyMessageObserver(Control myControl)
  {
    this.myControl = myControl;
    Application.AddMessageFilter(this);
  }

  public void Dispose()
  {
    Application.RemoveMessageFilter(this);
  }

  public bool PreFilterMessage(ref Message m)
  {
    switch (m.Msg)
    {
      case WM_LBUTTONDOWN:
      case WM_RBUTTONDOWN:
      case WM_MBUTTONDOWN:
        // Hier eigene Aktionen für this.myControl durchführen
    }

    return false; // Hier false zurückgeben, damit die Message vom getroffenen Control bearbeitet wird
  }
}

Über this.myControl und das HWnd im Message-Parameter kann man dann feststellen, wohin geklickt wurde und entsprechend reagieren.

dN!3L Themenstarter:in
2.891 Beiträge seit 2004
vor 12 Jahren

Hallo zusammen,

vielen Dank für die weiteren Antworten. Ich habe es erst einmal mit dem Vorschlag von IUndisposable gelöst. Dazu noch ein paar Anmerkungen:*Die Werte der verwendeten Konstanten:


public const int WM_LBUTTONDOWN = 513;
public const int WM_RBUTTONDOWN = 516;
public const int WM_MBUTTONDOWN = 519;

*Die Messages für die Mausklicks bekommt PreFilterMessage nur, wenn in das Fenster der aktuellen Anwendung geklickt wird. *Mithilfe des Control.LostFocus-Ereignis bekommt man auch die Klicks außerhalb des Anwendungsfensters mit.

Besten Gruß,
dN!3L

5.658 Beiträge seit 2006
vor 12 Jahren

Klingt kompliziert. PPK hatte erwähnt, daß die ComboBox mit einem eigenen Fenster arbeitet. Vielleicht wäre das noch eine Möglichkeit, weil wenn dann neben das Popup-Fenster geklickt wird, verliert es seinen Focus auf jeden Fall und man kann darauf reagieren, indem man es ausblendet.

Weeks of programming can save you hours of planning

dN!3L Themenstarter:in
2.891 Beiträge seit 2004
vor 12 Jahren

PPK hatte erwähnt, daß die ComboBox mit einem eigenen Fenster arbeitet. Vielleicht wäre das noch eine Möglichkeit[...]

Das finde ich (im aktuellen Anwendungsfall) komplizierter, da ich das Verhalten nicht für sowas wie ein ComboBoxDropdown oder ein Kontextmenü realisieren möchte. Ich brauche das für ein Control, dass sich ganz normal ins Fenster einbetten soll.

Ich habe mal einen Screenshot als Anhang dran: In der Normalansicht sieht man ein LinkLabel. Sobald man daraufklickt, wird das LinkLabel ausgeblendet und (in diesem Fall) eine Textbox eingeblendet. Sobald man nun wieder irgendwo daneben klickt, soll die Normalansicht wiederhergestellt werden.

dN!3L Themenstarter:in
2.891 Beiträge seit 2004
vor 12 Jahren

Und Achtung Fallstrick: Ich habe dummerweise nicht mittels Control.FromHandle (bzw. Control.FromChildHandle) und dem HWnd geguckt, welches Control konkret geklickt, sondern nur über das ClientRectangle geprüft, ob innerhalb des ContainerControls (von LinkLabel, TextBox, Lösch-Button etc.) geklickt wurde.
Das Funktioniert natürlich nicht, wenn z.B. in den DropDown-Bereich einer ComboBox oder eines DateTimePickers geklickt wird. (Dann gibt Control.FromHandle null zurück.)

Die DropDown-Variante (bsp. im Anhang) kann man übrigens relativ leicht durch einen ToolStripControlHost in Verbindung mit einem ToolStripDropDown realisieren.
Das hat dann die daneben-klick-stellt-Normalansicht-wieder-her-Funktionalität schon von Haus aus.