我的应用程序中有一个绑定命令的按钮。此按钮位于另一个控件内,该控件也会对鼠标点击做出反应。当按钮启用时,我得到了我期望的行为 - 单击按钮并触发命令,单击按钮外部但在容器控件内部,然后触发该操作。
不幸的是,当按钮被禁用时(通过命令的CanExecute方法),按钮上的点击会冒泡到容器控件。我不希望这样,我想要吞下点击 - 既不会触发命令也不会冒泡。
我试图通过创建一个继承自Button的新类来克服这个问题,但是以下方法似乎都没有在禁用的按钮上获得名称:
WPF路由事件系统是否完全忽略了禁用的控件?如果是这样的话,我可以得到我正在寻找的行为吗?
答案 0 :(得分:10)
RCGoforth的答案让我有90%的方式,但解决办法是不要在按钮后面放置一个矩形,因为冒泡事件在树上没有穿过兄弟姐妹。最后,我用ContentControl包围了按钮(因为矩形不能有子节点),它会在事件进一步发展之前吞噬事件:
<ContentControl MouseDown="ContentControl_MouseDown">
<Button Content="Click Test"
Padding="2"
Command="{Binding TestCommand}"/>
</ContentControl>
在背后的代码中:
private void ContentControl_MouseDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
}
或者在XAML中完全执行此操作(并增加代码的黑客级别......)
<Button>
<Button.Template>
<ControlTemplate>
<Button Content="Click Test"
Command="{Binding TestCommand}"/>
</ControlTemplate>
</Button.Template>
</Button>
答案 1 :(得分:2)
它不是很干净,但你可以在按钮后面放一个透明的矩形,吞下点击事件。
答案 2 :(得分:0)
您要做的是使用the overload that takes the handledEventsToo
parameter注册路由事件处理程序,并为该参数指定值true。这样,无论按钮是否实际处理事件,外部处理程序都将接收事件。这看起来像这样:
this.AddHandler(Mouse.MouseUpEvent, this.MyMouseUpHandler, true);
然后在您的处理程序中,您可以随时通过MouseButtonEventArgs
查看被点击的内容,是否已被处理等。例如,要检查另一个控件是否已经实际处理了该事件,您可以执行以下操作:
if(!args.Handled)
{
// handle it here instead
}
答案 3 :(得分:0)
更清晰,更可重用的解决方案是将此功能实现为附加属性。
使用服务/行动模式:
namespace Control.Services
{
public class UIElementService
{
public static readonly DependencyProperty HandleMouseEventsProperty = DependencyProperty.RegisterAttached("HandleMouseEvents",
typeof(bool), typeof(UIElementService), new FrameworkPropertyMetadata(false, UIElementService.HandleMouseEventsPropertyChanged));
static void HandleMouseEventsPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
{
FrameworkElement element = sender as FrameworkElement;
if (element == null)
return;
new HandleMouseEventsAction(element);
}
public static bool GetHandleMouseEvents(FrameworkElement target)
{
return (bool)target.GetValue(HandleMouseEventsProperty);
}
public static void SetHandleMouseEvents(FrameworkElement target, bool value)
{
target.SetValue(HandleMouseEventsProperty, value);
}
class HandleMouseEventsAction
{
UIElement m_Target;
MouseButtonEventHandler m_Handler;
internal HandleMouseEventsAction(FrameworkElement source)
{
m_Source = source;
m_Handler = new MouseButtonEventHandler(PreviewMouseLeftButtonUp);
m_Source.Loaded += OnSource_Loaded;
m_Source.Unloaded += OnSource_Unloaded;
}
void OnSource_Loaded(object sender, RoutedEventArgs e)
{
m_Source.AddHandler(Mouse.PreviewMouseUpEvent, m_Handler, true);
}
void OnSource_Unloaded(object sender, RoutedEventArgs e)
{
m_Source.RemoveHandler(Mouse.PreviewMouseUpEvent, m_Handler);
}
void PreviewMouseLeftUIElementUp(object sender, MouseUIElementEventArgs e)
{
e.Handled = true;
}
}
}
}
然后使用,导入命名空间。
<Button sv:UIElementService.HandleMouseEvents="True" />
或
<ContentControl sv:UIElementService.HandleMouseEvents="True">
<Button Content="Click Test" Padding="2" Command="{Binding TestCommand}"/>
</ContentControl>
我没有测试过这个(现在没时间)。我相信即使被禁用,该动作仍将获得鼠标事件。
HTH,
丹尼斯
答案 4 :(得分:0)
我创建了一个在ContentPresenter
及其父级之间插入Button
的行为(实际上有效)。 ContentPresenter
禁用Button
时,<Button ...>
<i:Interaction.Behaviors>
<behaviors:SwallowMouseClicksWhenDisabled />
</i:Interaction.Behaviors>
</Button>
会吞下鼠标。该行为使用了一些基于this answer代码的扩展方法。使用它非常简单:
// the behavior (could also be an attached behavior)
public class SwallowMouseClicksWhenDisabled : Behavior<FrameworkElement>
{
protected override void OnAttached()
{
var oldParent = AssociatedObject.Parent;
oldParent.RemoveChild(AssociatedObject);
var newParent = new ContentPresenter { Content = AssociatedObject };
oldParent.AddChild(newParent);
newParent.PreviewMouseDown += OnPreviewMouseEvent;
newParent.PreviewMouseUp += OnPreviewMouseEvent;
}
private void OnPreviewMouseEvent(object sender, MouseButtonEventArgs e)
{
e.Handled = AssociatedObject.IsEnabled == false;
}
}
// the extension methods
public static class DependencyObjectExtensions
{
public static void AddChild(this DependencyObject parent, UIElement child)
{
var panel = parent as Panel;
if (panel != null)
{
panel.Children.Add(child);
return;
}
var decorator = parent as Decorator;
if (decorator != null)
{
decorator.Child = child;
return;
}
var contentPresenter = parent as ContentPresenter;
if (contentPresenter != null)
{
contentPresenter.Content = child;
return;
}
var contentControl = parent as ContentControl;
if (contentControl != null)
{
contentControl.Content = child;
return;
}
// maybe more
}
public static void RemoveChild(this DependencyObject parent, UIElement child)
{
var panel = parent as Panel;
if (panel != null)
{
panel.Children.Remove(child);
return;
}
var decorator = parent as Decorator;
if (decorator != null)
{
if (Equals(decorator.Child, child))
{
decorator.Child = null;
}
return;
}
var contentPresenter = parent as ContentPresenter;
if (contentPresenter != null)
{
if (Equals(contentPresenter.Content, child))
{
contentPresenter.Content = null;
}
return;
}
var contentControl = parent as ContentControl;
if (contentControl != null)
{
if (Equals(contentControl.Content, child))
{
contentControl.Content = null;
}
return;
}
// maybe more
}
}
以下是来源:
import pandas as pd
ordered_satisfaction = ['Very Unhappy', 'Unhappy', 'Neutral', 'Happy', 'Very Happy']
df = pd.DataFrame({'satisfaction': ['Mad', 'Happy', 'Unhappy', 'Neutral']})
df.satisfaction = df.satisfaction.astype('category', ordered=True, categories=ordered_satisfaction).cat.codes
print df