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?
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
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... 😕
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,
Dass mouse down erenis hilft
Hm, das wird auch nicht ausgelöst, wenn man auf ein ChildControl klickt.
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
Die comboBox arbeitet irgend wie mit einem zweiten fenster, einem (ChildWindow).
Diese nachricht wird ausgelößt nachdem eine Combobox geschlossen wird.
WM_PARENTNOTIFY Message
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
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.
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
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
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.
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.