Hallo,
ich habe eine Controlklasse, diese dient als spezieller Container für diverse Grafiken.
Was ich nun machen will ist wenn man in ein bestimmtes Feld mit der Maus geht (Beispiel 20x20 Feld unten links in der Ecke), soll ein kleines Popup Fenster geöffnet werden.
Ich würde im Basiscontainer Element dafür das MouseMove Event regestrieren und halt auf den Bereich hin abfragen und dann das Fenster anzeigen. Jedoch da es ja ein Container ist, können sich andere Controls darauf befinden und diesen Bereich überdecken, sodass der Event nicht mehr greift -_-.
Ich habe dazu zwei Fragen. Ist der MosueMove Event der richtige Ansatz? Ich meine gehört zu haben das man soetwas anders abfragt. Vielleicht WinProc??
Wie kann ich diesen Event über die Childcontrols setzten, sodass dieser gefeuert wird auch wenn ich über die Childcontrols gehe?
zu 2.
foreach(Control ctrl in this.Controls)
ctrl.MouseMove += new ..
Der Ansatz würde funktionieren wenn ich Events weitergeben könnte. Dann so:
ContainerKlasse()
{
this.MouseMove += new MouseEventHandler(Container_MouseMove);
this.ControlAdded += new ControlEventHandler(control_ControlAdded);
}
void control_ControlAdded(object sender, ControlEventArgs e)
{
Control con = (Control)sender;
Control added = con.Controls[con.Controls.Count-1];
added.MouseMove += new MouseEventHandler(added_MouseMove);
added.ControlAdded += new ControlEventHandler(control_ControlAdded);
}
void added_MouseMove(object sender, MouseEventArgs e)
{
((Control)sender).Parent.OnMouseMove(e);
}
Aber so einfach geht das ja nicht oder sehe ich was falsch?
void control_ControlAdded(object sender, ControlEventArgs e)
{
Control con = (Control)sender;
Control added = con.Controls[con.Controls.Count-1];
added.MouseMove += new MouseEventHandler(added_MouseMove);
//added.ControlAdded += new ControlEventHandler(control_ControlAdded);
}
Das würde gehen, aber bedenke, die Koordinaten werden vom 0 Punkt des Childs aus jeweils berechnet! Wenn also Parent e.X - Child e.X machst wirst immer = 0 erhalten da Parent e.X = 0 und Child e.X = 0 ist. 🙂
Klingt zwar einfachc oder logisch, aber wenn so etwas berechnen möchtest denk dran, über Parent.Location und Child.Location (kannst auch .ClientRect wenn auch den Rand ausschließen möchtest). Über den sender identifizierst ja die Controls.
Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(
Das geht doch nicht weil dieser Teil nicht funktioniert, weil OnMouseMove Protected ist:
void added_MouseMove(object sender, MouseEventArgs e)
{
((Control)sender).Parent.OnMouseMove(e);
}
Das heisst meine Basisklasse kriegt nie mit wann ein Mousemove auf seine Childs gemacht wird, weil die es nicht übergeben können an die Parents...
Muh, hab mich verlesen, hatte es so verstanden vom Child zum Parent. Du willst aber die Parent MouseMove zum Client 😉
Eine Lösung dafür wäre ein lowlevel hook auf den eigenen Prozess und das Handle des Parents , praktischerweise ist dieser ja dme Child bekannt.
Unter folgenden Link findest du einen global hookLink, shcmeiß das LoadLibrary weg, stell das SetWindowHook um.
SetWindowsHookEx(WH_MOUSE, MouseHookProcedure, <ParentHandle>, AppDomain.GetCurrentThreadId());
Kannst auch nen ThreadHook schreiben, und das <ParentHandle> weglassen, da es logisch ist das die Maus nur koordinaten des äussersten Containers versenden kann auf dem aktuellen GUI Thread. Ergo hast imemr das Parent.
Sieht so aus:
SetWindowsHookEx(WH_MOUSE, MouseHookProcedure, (IntPtr)0, AppDomain.GetCurrentThreadId());
Gibt aber auch andere sehr schöne hooks hier im Forum sogar in C++ 🙂
Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(
Wow das sieht etwas zu hoch für mich aus. Muss erstmal verstehen was du meinst. Aber vielen Dank dafür, jetzt hab ich ja was woran ich mich setzten kann. Bestimmt melde ich mich nochmal zu dem Thema 😉
Hrm, es geht auch etws einfacher. Du kannst ja auf deinen Controls eine Schnittstelle implementieren welche das event MouseEventHandler OnParentMouseMove; beinhaltet und beim Adden der controls so wie oben das event auf jene Controls mit dem passenden interface binden. Dann überschreibst beim Parent Control die OnMouseMove Methode und feuerst das Event ab. Und schon kannsta uf deinen childcontrols auf das Event reagieren.
Also es gibt viele Möglichkeiten das zu realisieren 🙂
Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(
Das Problem dabei ist nur das ich alle Controls die ich einfüge erstmal anpassen müsste (Also das Interface implementieren). Das heisst die Klasse wäre ja dann nicht mehr allgemeingültig.
Hrm, du kannst das auch über Win API abbilden was dir Khalid als Link reingestellt hat. Indem mit PostmEssage bei Protected override OnMouseMove beim Parentcotnrol ebenso durch alle Controls durchgehst und an WM_MOUSEMOVE über deren Handle die Nachricht weiterleitest, kannst als lParam ja das Parenthandle mit übergeben. Sollte deren eigener MouseMove dennoch interpretieren können. Wäre das selbe wie halt bei Khalid's beispiel nur nen fitzelchen weniger Code.
Wie vernichtet stand Andreas unter den flammenden Augen seiner Kunden.
Ihm war's, als stünde des Schicksals dunkle Wetterwolke über seinem Haupte X(
sein erster einsatz ist doch ganz ok.
die einzige änderung ist doch hier nötig:
void added_MouseMove(object sender, MouseEventArgs e)
{
((Control)sender).Parent.OnMouseMove(e);
}
hier sollte man einfach statt parents OnMouseMove aufzurufen, gleich die richtigen koordinaten berechnen.
es geht auch ganz einfach: also von den sender-control koordinaten in die screen koordinaten und dann in die client koordinaten des hauptcontainers (Controlklasse).