我可以扩展Button来添加RightClick事件吗?这样就可以保持图形的副作用
本文关键字:就可以 图形 副作用 Button 扩展 添加 RightClick 事件 我可以 | 更新日期: 2023-09-27 18:29:30
我正在尝试扩展Button以添加RightClick事件。
我的客户想要一个按钮来做不同的事情,这取决于你是左键点击还是右键点击。我本以为会有一个简单的右键点击事件,但事实并非如此。
我更希望Button的视觉行为与之前存在的Click事件相同,但事实证明这很难。按钮有许多图形行为,当您单击和拖动按钮时会发生这些行为。
- 当您向下单击时,按钮会降低。如果您拖动降低的按钮,它会升高(例如取消降低)。您拖动的任何其他按钮都将忽略它
- 当您向后拖动原始按钮时,它将再次降低
- 如果您拖动并释放,则原始按钮的状态应重置(即,您不能再次单击并拖动)
如果左键点击的视觉效果与右键点击的不匹配,这些小的图形怪癖看起来会很粗糙。
当前我被困在这个问题上:如果右键单击并按住按钮,然后拖动按钮,我如何检测用户是否取消单击?我需要知道这一点,这样我才能知道在重新进入时不要重新按下按钮。
一个更广泛的问题:我是否走上了正确的轨道?我找不到以前做过这种事的人。我的代码在下面。
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;
}
}
感谢我对另一个问题的回答,这就是我的想法。
XP和Win7的行为似乎有一些不同。我需要在Win7上进一步测试。
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);
}
// Subclasses can't invoke this event directly, so supply this method
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;
}
}
}
如果查看ButtonBase
的源代码,您会发现很难轻松复制OnMouseLeftButtonDown
和OnMouseLeftButtonUp
覆盖中发生的内容。
一个似乎工作得很好的简单破解方法是从Button
派生如下:
public class MyButton : Button
{
protected override void OnMouseRightButtonDown(MouseButtonEventArgs e)
{
base.OnMouseRightButtonDown(e); // this line probably optional/not required
base.OnMouseLeftButtonDown(e);
}
protected override void OnMouseRightButtonUp(MouseButtonEventArgs e)
{
base.OnMouseRightButtonUp(e); // this line probably optional/not required
base.OnMouseLeftButtonUp(e);
}
}
然后在Xaml中使用<MyButton>
代替<Button>
。
我不能保证这在所有情况下都能正确工作,但它似乎确实能按要求工作,因为右键或左键单击时按钮的视觉行为是相同的。
只是添加了我自己的2c。这是基于@Grant给出的答案,并进行了以下更改:
-
这适当地使用
_rightButtonDown
标志而不是CaptureMouse
属性来确定处理,因为CaptureMouse
可能已经在其他地方设置(即,这遵循适当的封装) -
这支持允许值为
Press
的ClickMode
属性。 -
这正确地使用了
OnRightClick
处理程序,该处理程序的名称现在不仅遵循标准约定,而且还处理引发RightClick
事件的所有调用,而不是复制代码。它也被标记为virtual
,以正确地支持子类功能,因为如果覆盖该函数,则可以处理/阻止所有RightClick
事件。 -
我将其命名为EnhancedButton,以防我想添加其他功能。
-
我已经包含了一个例子,说明如何定义一种样式,使其正确地显示在工具栏中
注意:在控件上实现RightClick事件的正确方法是作为RoutedEvent,而不是标准CLR事件。然而,为了使这个示例保持简单,我将把它留给读者来实现。
这是EnhancedButton类的代码:
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
}
以下是如何定义样式,使其看起来像所有其他工具栏按钮一样。将其添加到工具栏的资源中,或者更好的是,设置工具栏的样式以在样式中设置它,这样您就不必在任何地方手动添加它。
<Style TargetType="{x:Type myControls:EnhancedButton}" BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" />
现在,它是标准Button
控件的更兼容的插件替代品。
当然可以,为什么不呢?
只需为Mouse Up事件实现Events,并在那里检查鼠标右键是否已按下-如果为true,则调用您之前添加的代理/事件,例如OnRightMouseClick。
看看路由事件的MSDN页面,是的,你走在了正确的轨道上。
问候,
当然,wpf允许您将命令绑定到控件。首先连接窗口的命令绑定。
<Window.CommandBindings>
<CommandBinding Command="{x:Static custom:Window1.RightClickCommand}"
Executed="YourRightClickMethodInCSharpFile" />
</Window.CommandBindings>
然后在按钮上注册右键绑定
<Button Content="Ima Button!">
<Button.InputBindings>
<MouseBinding Command="{x:Static custom:Window1.RightClickCommand}"
MouseAction="RightClick" />
</Button.InputBindings>
</Button>
来源:WPF命令绑定-鼠标点击
您可以使用PreviewMouseDown事件。它会像这个
private void buttonTest_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.RightButton == MouseButtonState.Pressed)
{
MessageBox.Show("Right");
}
else if (e.LeftButton == MouseButtonState.Pressed)
{
MessageBox.Show("Left");
}
e.Handled = true;
}