Laden...

MouseLeave Event wird nicht zuverlässig ausgelöst

Erstellt von Ramokthan vor 11 Jahren Letzter Beitrag vor 11 Jahren 1.658 Views
R
Ramokthan Themenstarter:in
23 Beiträge seit 2012
vor 11 Jahren
MouseLeave Event wird nicht zuverlässig ausgelöst

Hallo,

da ich neu hier bin versuch ich mein erstes Thema so gut wie möglich zu gestalten ^^

Mein Problem: Ich habe im Rahmen einer mittelgroßen Silverlightanwendung an mehreren Stellen Menü-Popups (vom Typ StackPanel) die teils durch MoueOver Events oder über MouseRightClick ausgelöst werden. Das funktioniert auch zuverlässig, nun habe ich jedoch das Problem, dass diese Menüs nicht immer Ordnungsgemäss geschlossen werden wenn ich mit der Maus den Stackpanel verlasse. "Nicht immer" heißt in diesem Fall: wenn ich mit der Maus sehr schnell den Bereich des Stackpanels verlasse, verlasse ich ihn (vergleichsweise) langsam, wird das Menü bzw. der Stackpanel ordnungsgemäß geschlossen (ausgeblendet).
Ich habe mir diesbezüglich schon Gedanken über Workarounds gemacht wie zb die Archivierung aller geöffneten Mouseover Menüs und nach jeder Mausbewegung zu prüfen ob die Maus noch auf einem von diesen Ruht, aber eine ideale Lösung scheint mir dies nicht (zumal das sich nicht sehr performant anhört).

Ich versuche mal mit ein Paar codebeispielen ein Bild zu geben wie das ganze aufgebaut ist, grundsätzlich funktioniert es ja, nur scheinbar kommt das Mouseleave Event nicht mit der Geschwindigkeit der Maus mit. ^^

Der Konstruktor der Menü Klasse:

public CContextMenu(object objMain, Canvas objCanvas)
        {
            if (objMain != null)
            {
                if (this.objMain.getCurrentUIElement() != null && this.objMain.objContextMenu == null)
                             this.objMain.getCurrentUIElement().MouseEnter += new MouseEventHandler(CContextMenu_MouseOver);
            }

            this.objCanvas = objCanvas;
        }

Die (eine von vielen 😄 ) Initialisierung:

if (this.objContextMenu == null) this.objContextMenu = new CContextMenu(this, this.objCanvas, this.objTextBlock);
            else this.objContextMenu.clearMenues();

Die Funktionen (sehr aufs wesentliche gekürzt, ich hoffe nicht zuviel):


public void CContextMenu_MouseOver(object sender, MouseEventArgs e)
        {
            CContextMenu_MouseRightButtonDown(sender,null);
        }
        
        // Mouse right click event for visual object
        public void CContextMenu_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {

if (this.objContextMenu == null)
                {
                    this.objContextMenu = new Border();
                    ((Border)this.objContextMenu).BorderBrush = new SolidColorBrush(Color.FromArgb(255, 153, 153, 153));
                    ((Border)this.objContextMenu).BorderThickness = new Thickness(1);
                    LinearGradientBrush objBrush = new LinearGradientBrush();
                    objBrush.EndPoint = new Point(0.5, 1);
                    objBrush.StartPoint = new Point(0.5, 0);
                    GradientStop objGradientStop = new GradientStop();
                    objGradientStop.Color = Colors.White;
                    objBrush.GradientStops.Add(objGradientStop);
                    objGradientStop = new GradientStop();
                    objGradientStop.Color = Color.FromArgb(255, 150, 183, 249);
                    objGradientStop.Offset = 1;
                    objBrush.GradientStops.Add(objGradientStop);
                    (this.objContextMenu as Border).Background = objBrush;
                    DropShadowEffect objEffect = new DropShadowEffect();
                    this.objContextMenu.Effect = objEffect;

                    StackPanel objStackPanel = new StackPanel();
                    objStackPanel.HorizontalAlignment = HorizontalAlignment.Left;
                    objStackPanel.VerticalAlignment = VerticalAlignment.Top;

                    objStackPanel.MouseLeave += new MouseEventHandler(this.ContextMenu_MouseLeave);

((Border)this.objContextMenu).Child = objStackPanel;
                    this.objContextMenu.SetValue(Canvas.ZIndexProperty, 100);
                    this.objContextMenu.UpdateLayout();
                    this.objContextMenu.Visibility = Visibility.Collapsed;

CSingelton.objMainPage.OutCanvas.Children.Add(this.objContextMenu);
}
}

// Event for mouse leave from context menu
        protected virtual void ContextMenu_MouseLeave(object sender, object e)
        {
            if (this.objContextMenu != null) this.objContextMenu.Visibility = Visibility.Collapsed;
        }

Das sollte und bewirkt auch was es sollte: ein Öffnen des Stackpanels nach dem Kontakt mit dem Mauszeiger und ein Schließen beim (langsamen) verlassen. Nur möchte ich einfach diesen Wust nicht haben von offenen nicht benutzten Menüs (Auch wenn man daraus ein Spiel machen könnte: wieviele Menüs schaffst du gleichzeitig offen zu haben 😄 ) wenn man mit der Maus schnell über ein Objekt fährt, da das Menü sich dann zwar öffnet, aber nicht mehr korrekt schließt, sollte man mit der Maus zu schnell sein. Die Menüs lassen sich zwar im nachhinein schließen wenn man mit der Maus wieder auf das Menü geht und dann dieses wieder (langsam) verlässt, aber auch diesen Workaround, das finde ich, sollte man doch irgendwie vermeiden können.

Habt ihr da eine Idee an was es da hängen könnte oder ist das ein allgemeines Problem?

Grüße,
Ramokthan

2.891 Beiträge seit 2004
vor 11 Jahren

Das ist ein allgemeines Problem. Tritt z.B. auch bei Winforms-Anwendungen auf.

Lösen kann man das z.B. durch einen Timer, der beim Einblenden des Menüs ausgelöst wird und dann (nach einer gewissen Zeit) prüft, ob sich der Mauszeiger noch über dem Menü-Control (bzw. plus einen gewissen Toleranzbereich drumherum) befindet.
Das hat auch den Vorteil, dass man nicht die ganze Zeit den Cursor exakt über dem Menü-Control befinden muss. Denn eigentlich verschwinden Menüs auch gar nicht sofort, wenn man sie verlässt.

R
Ramokthan Themenstarter:in
23 Beiträge seit 2012
vor 11 Jahren

Okay, allgemeines problem und nicht meine doofheit ^^

Ich werde das mal so ins Auge fassen mit dem Timer, schaffen werd ich das selber, danke für den Tipp. 👍