5 Stimmen

Kann ich Button erweitern, um ein RightClick-Ereignis hinzuzufügen, sodass auch die grafischen Seiteneffekte beibehalten werden?

Ich versuche, Button zu erweitern, um ein Rechtsklick-Ereignis hinzuzufügen.

Mein Kunde möchte, dass ein Button je nach Linksklick oder Rechtsklick verschiedene Dinge tut. Ich hatte erwartet, dass es ein einfaches Ereignis für Rechtsklick gibt, aber anscheinend gibt es keins.

Ich möchte, dass das visuelle Verhalten des Buttons identisch mit dem bereits vorhandenen Klick-Ereignis ist, aber das gestaltet sich schwierig. Der Button hat viele grafische Verhaltensweisen, die auftreten, wenn man auf den Button klickt und daraufhin zieht.

  • Wenn Sie klicken, wird der Button heruntergedrückt. Wenn Sie den heruntergedrückten Button ziehen, wird er wieder angehoben (d. h. nicht mehr heruntergedrückt). Andere Buttons, über die Sie ziehen, ignorieren dies.
  • Wenn Sie wieder auf den ursprünglichen Button ziehen, wird er erneut heruntergedrückt.
  • Wenn Sie den Button verlassen und dann loslassen, sollte der Zustand des ursprünglichen Buttons zurückgesetzt werden (d. h. Sie können nicht erneut darauf klicken und ziehen).

Diese kleinen grafischen Eigenheiten sehen unsauber aus, wenn die Linksklick-Visuals nicht mit den Rechtsklick-Visuals übereinstimmen.

Aktuell bleibe ich in diesem Punkt stecken: Wenn Sie mit Rechtsklick auf den Button klicken und dann ziehen, wie erkenne ich, wenn der Benutzer den Klick löst? Ich muss das wissen, damit ich weiß, dass der Button bei erneutem Betreten nicht erneut heruntergedrückt werden soll.

Eine allgemeinere Frage: Bin ich überhaupt auf dem richtigen Weg? Ich konnte niemanden finden, der das schon einmal gemacht hat. Mein Code befindet sich unten.

public class RightClickButton : Button
{
    public event RoutedEventHandler RightClick;

    public RightClickButton()
    {
        this.MouseRightButtonDown += new System.Windows.Input.MouseButtonEventHandler(RightClickButton_MouseRightButtonDown);
        this.MouseRightButtonUp += new System.Windows.Input.MouseButtonEventHandler(RightClickButton_MouseRightButtonUp);
        this.MouseEnter += new System.Windows.Input.MouseEventHandler(RightClickButton_MouseEnter);
        this.MouseLeave += new System.Windows.Input.MouseEventHandler(RightClickButton_MouseLeave);
    }

    void RightClickButton_MouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        this.IsPressed = true;
    }

    void RightClickButton_MouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        this.IsPressed = false;
        if (RightClick != null)
            RightClick.Invoke(this, e);
    }

    void RightClickButton_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
    {
        if (this.IsPressed)
            this.IsPressed = false;
    }

    void RightClickButton_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
    {
        if (this.IsFocused && Mouse.RightButton == MouseButtonState.Pressed)
            this.IsPressed = true;
    }
}

3voto

Grant Birchmeier Punkte 16863

Dank einer Antwort auf meine andere Frage bin ich zu folgendem Ergebnis gekommen.

Es scheint Unterschiede im Verhalten zwischen XP und Win7 zu geben. Ich werde weitere Tests auf Win7 durchführen müssen.

public class RightClickButton : Button
{
    public event RoutedEventHandler RightClick;

    private bool _clicked = false;

    public RightClickButton()
    {
        this.MouseRightButtonDown += new System.Windows.Input.MouseButtonEventHandler(RightClickButton_MouseRightButtonDown);
        this.MouseRightButtonUp += new System.Windows.Input.MouseButtonEventHandler(RightClickButton_MouseRightButtonUp);
    }

    // Subklassen können dieses Ereignis nicht direkt aufrufen, also liefern Sie diese Methode
    protected void TriggerRightClickEvent(System.Windows.Input.MouseButtonEventArgs e)
    {
        if (RightClick != null)
            RightClick(this, e);
    }

    void RightClickButton_MouseRightButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        this.IsPressed = true;
        CaptureMouse();
        _clicked = true;
    }

    void RightClickButton_MouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        ReleaseMouseCapture();

        if(this.IsMouseOver && _clicked)
        {
            if (RightClick != null)
                RightClick.Invoke(this, e);
        }

        _clicked = false;
        this.IsPressed = false;
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {
        base.OnMouseMove(e);

        if (this.IsMouseCaptured)
        {
            bool isInside = false;

            VisualTreeHelper.HitTest(
                this,
                d =>
                {
                    if (d == this)
                    {
                        isInside = true;
                    }

                    return HitTestFilterBehavior.Stop;
                },
                ht => HitTestResultBehavior.Stop,
                new PointHitTestParameters(e.GetPosition(this)));

            if (isInside)
                this.IsPressed = true;
            else
                this.IsPressed = false;
        }
    }
}

1voto

Phil Punkte 40767

Wenn Sie den Quellcode für ButtonBase betrachten, werden Sie feststellen, dass es schwierig wäre, einfach zu duplizieren, was in den Überschreibungen von OnMouseLeftButtonDown und OnMouseLeftButtonUp passiert.

Ein einfacher Hack, der anscheinend ziemlich gut funktioniert, besteht darin, von Button abzuleiten, wie folgt:

public class MyButton : Button
{
    protected override void OnMouseRightButtonDown(MouseButtonEventArgs e)
    {
        base.OnMouseRightButtonDown(e); // diese Zeile wahrscheinlich optional/nicht erforderlich
        base.OnMouseLeftButtonDown(e);
    }

    protected override void OnMouseRightButtonUp(MouseButtonEventArgs e)
    {
        base.OnMouseRightButtonUp(e); // diese Zeile wahrscheinlich optional/nicht erforderlich
        base.OnMouseLeftButtonUp(e);
    }
}

Verwenden Sie dann anstelle von in Ihrem Xaml.

Ich kann nicht garantieren, dass dies in allen Szenarien korrekt funktioniert, aber es scheint zu funktionieren, wie erforderlich, dass das visuelle Verhalten des Buttons gleich ist, wenn Sie mit der rechten oder linken Maustaste klicken.

1voto

Mark A. Donohoe Punkte 25434

Nur noch meine 2 Cent hinzuzufügen. Dies basiert auf der Antwort von @Grant mit den folgenden Änderungen:

  1. Dies verwendet ordnungsgemäß das _rightButtonDown-Flag, nicht die CaptureMouse-Eigenschaft zur Bestimmung der Verarbeitung, da CaptureMouse möglicherweise anderswo festgelegt wurde (d.h. dies entspricht der ordnungsgemäßen Kapselung).

  2. Dies unterstützt die ClickMode-Eigenschaft und ermöglicht einen Wert von Press.

  3. Dies verwendet ordnungsgemäß den OnRightClick-Handler, dessen Name nicht nur jetzt der Standardkonvention folgt, sondern der auch alle Aufrufe zum Auslösen des RightClick-Ereignisses behandelt, anstatt den Code zu duplizieren. Es wurde auch als virtual markiert, um die Subclass-Fähigkeiten ordnungsgemäß zu unterstützen, so dass wenn Sie diese Funktion überschreiben, können Sie alle RightClick-Ereignisse behandeln/blockieren.

  4. Ich habe es EnhancedButton genannt, falls ich zusätzliche Funktionalitäten hinzufügen möchte.

  5. Ich habe ein Beispiel dafür aufgenommen, wie Sie einen Stil definieren würden, um sicherzustellen, dass dies ordnungsgemäß in einer Symbolleiste angezeigt wird

Hinweis: Der ordnungsgemäße Weg, das RightClick-Ereignis auf einem Steuerelement zu implementieren, ist als RoutedEvent, nicht als Standard-CLR-Ereignis. Allerdings überlasse ich es dem Leser, dies zu implementieren, um dieses Beispiel einfach zu halten.

Hier ist der Code für die EnhancedButton-Klasse:

public class EnhancedButton : Button
{
    private bool _rightButtonDown = false;

    public EnhancedButton()
    {
        MouseRightButtonDown += RightClickButton_MouseRightButtonDown;
        MouseRightButtonUp   += RightClickButton_MouseRightButtonUp;
    }

    #region RightClick Event

        public event RoutedEventHandler RightClick;

        protected virtual void OnRightClick(MouseButtonEventArgs e)
        {
            RightClick?.Invoke(this, e);
        }

    #endregion RightClick Event

    #region Event Handlers

        private void RightClickButton_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            IsPressed = true;

            _rightButtonDown = true;
            CaptureMouse();

            if(ClickMode == ClickMode.Press)
                OnRightClick(e);
        }

        private void RightClickButton_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            if(!_rightButtonDown)
                return;

            ReleaseMouseCapture();

            IsPressed = false;

            if(IsMouseOver && ClickMode == ClickMode.Release)
                OnRightClick(e);

            _rightButtonDown = false;
        }

    #endregion Event Handlers

    #region Overrides

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if(!_rightButtonDown)
                return;

            bool isInside = false;

            VisualTreeHelper.HitTest(this, d =>
            {
                if (d == this)
                    isInside = true;

                return HitTestFilterBehavior.Stop;
            },
            ht => HitTestResultBehavior.Stop,
            new PointHitTestParameters(e.GetPosition(this)));

            IsPressed = isInside;
        }

    #endregion Overrides
}

Und so definieren Sie einen Stil, damit dieser wie alle anderen Schaltflächen in der Symbolleiste angezeigt wird. Fügen Sie dies zu den Ressourcen Ihrer Symbolleiste hinzu oder noch besser, definieren Sie Ihre Symbolleisten, um dies im Stil festzulegen, damit Sie es nicht überall manuell hinzufügen müssen.

</code></pre>

<p>Jetzt ist es eine kompatiblere Plug-and-Play-Alternative zur Standard-Button-Steuerelement.</p></x-turndown>

0voto

Mario Fraiß Punkte 1085

Natürlich kannst du das machen, warum nicht?

Implementiere einfach die Events für das Mouse-Up Event und überprüfe dort, ob die rechte Maustaste gedrückt wurde - wenn ja, rufe dann deinen Delegierten/Event auf, den du zuvor hinzugefügt hast, z.B. OnRightMouseClick.

Schau dir die MSDN-Seite zu Routed Events an - und ja, du bist auf dem richtigen Weg.

Viele Grüße,

0voto

Rob Rodi Punkte 3468

Sicher, mit wpf kannst du Befehle an Steuerelemente binden. Verkabeln Sie zuerst die Befehlsbindungen des Fensters.

Registrieren Sie dann die Rechtsklickbindung für die Schaltfläche

Quelle: WPF Command bindings - Mausklicks

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X