模拟Click with MouseUp和MouseDown事件或其他方法的最佳方法是什么?

H.B*_*.B. 29 wpf controls click mouseevent

在WPF大多数控件具有MouseUpMouseDown事件(和鼠标按钮特有的变化),但不是一个简单的Click,可马上使用的事件.如果你想使用这些事件进行类似点击的行为,你需要处理我认为有点痛苦的事件.

最明显的问题是,你不能简单地忽略MouseDown事件,因为如果你点击启动另一个控件,它被释放了,只有处理控制MouseUp你应该点击就会触发,而它真的不应该:两个MouseUpMouseDown以上相同的控制应该发生.

所以如果有的话,我会对这个一般性问题更优雅的解决方案感兴趣.


注意:有几个很好的解决方案可以在下面看到,我选择接受Rachel的答案,因为它似乎很受欢迎,但另外我想添加以下注释:

Rachel的按钮答案非常简洁明了,但是您需要将实际控件包装在一个按钮中,在某些情况下,您可能不会真正将控件视为按钮,因为它可以被单击(例如,如果它更像是超链接),进一步你需要每次都引用一个模板.

Rick Sladkey的行为答案更直接地回答了如何模拟点击/使控件可点击的原始问题,缺点是你需要引用System.Windows.Interactivity并喜欢Rachel的解决方案,它会夸大Xaml代码.

我的附加事件答案的优点是在Xaml-Markup方面非常接近正常的点击事件,这可以用一个属性来完成,我看到的唯一问题是代码中的事件附件没有干净地封装(如果有人知道修复此问题,请在答案中添加评论).

Rac*_*hel 17

我会使用一个Button控件并覆盖它Button.Template直接显示内容.

<ControlTemplate x:Key="ContentOnlyTemplate" TargetType="{x:Type Button}">
    <ContentPresenter />
</ControlTemplate>

<Button Template="{StaticResource ContentOnlyTemplate}">
    <Label Content="Test"/>
</Button>
Run Code Online (Sandbox Code Playgroud)

  • @HB:这是使用WPF的预期解决方案.控件"看起来很",因为它们可以以您选择的任何方式进行模板化 - 因此任何需要"可点击"的控件都可以是带有自定义模板的按钮. (2认同)

Ric*_*key 12

以下是您可以添加到任何元素的行为,以便ButtonBase.Click使用常规按钮逻辑引发事件:

public class ClickBehavior : Behavior<FrameworkElement>
{
    protected override void OnAttached()
    {
        AssociatedObject.MouseLeftButtonDown += (s, e) =>
        {
            e.Handled = true;
            AssociatedObject.CaptureMouse();
        };
        AssociatedObject.MouseLeftButtonUp += (s, e) =>
        {
            if (!AssociatedObject.IsMouseCaptured) return;
            e.Handled = true;
            AssociatedObject.ReleaseMouseCapture();
            if (AssociatedObject.InputHitTest(e.GetPosition(AssociatedObject)) != null)
                AssociatedObject.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

注意使用鼠标捕获/释放和输入命中测试检查.有了这种行为,我们可以编写这样的点击处理程序:

<Grid>
    <Rectangle Width="100" Height="100" Fill="LightGreen" ButtonBase.Click="Rectangle_Click">
        <i:Interaction.Behaviors>
            <utils:ClickBehavior/>
        </i:Interaction.Behaviors>
    </Rectangle>
</Grid>
Run Code Online (Sandbox Code Playgroud)

和背后的代码:

    private void Rectangle_Click(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine("Code-behind: Click");
    }
Run Code Online (Sandbox Code Playgroud)

很容易将其转换为所有代码隐藏; 重要的部分是捕获和点击逻辑.

如果您不熟悉行为,请安装Expression Blend 4 SDK并添加此命名空间:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
Run Code Online (Sandbox Code Playgroud)

并添加System.Windows.Interactivity到您的项目.

编辑:

以下是如何将单击行为附加到代码隐藏中的元素并为click事件添加处理程序:

void AttachClickBehaviors()
{
    AttachClickBehavior(rectangle1, new RoutedEventHandler(OnAttachedClick));
}

void OnAttachedClick(object sender, RoutedEventArgs e)
{
    Debug.WriteLine("Attached: Click");
}

// Reusable: doesn't need to be in the code-behind.
static void AttachClickBehavior(FrameworkElement element, RoutedEventHandler clickHandler)
{
    Interaction.GetBehaviors(element).Add(new ClickBehavior());
    element.AddHandler(ButtonBase.ClickEvent, clickHandler);
}
Run Code Online (Sandbox Code Playgroud)


H.B*_*.B. 5

好吧,只是想我会玩附加事件,看看我会在哪里得到它,以下似乎在大多数情况下都有效,可以使用一些改进/调试:

public static class Extensions
{
    public static readonly RoutedEvent ClickEvent = EventManager.RegisterRoutedEvent(
        "Click",
        RoutingStrategy.Bubble,
        typeof(RoutedEventHandler),
        typeof(UIElement)
        );

    public static void AddClickHandler(DependencyObject d, RoutedEventHandler handler)
    {
        UIElement element = d as UIElement;
        if (element != null)
        {
            element.MouseLeftButtonDown += new MouseButtonEventHandler(element_MouseLeftButtonDown);
            element.MouseLeftButtonUp += new MouseButtonEventHandler(element_MouseLeftButtonUp);
            element.AddHandler(Extensions.ClickEvent, handler);
        }
    }

    public static void RemoveClickHandler(DependencyObject d, RoutedEventHandler handler)
    {
        UIElement element = d as UIElement;
        if (element != null)
        {
            element.MouseLeftButtonDown -= new MouseButtonEventHandler(element_MouseLeftButtonDown);
            element.MouseLeftButtonUp -= new MouseButtonEventHandler(element_MouseLeftButtonUp);
            element.RemoveHandler(Extensions.ClickEvent, handler);
        }
    }

    static void element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        UIElement uie = sender as UIElement;
        if (uie != null)
        {
            uie.CaptureMouse();
        }
    }
    static void element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        UIElement uie = sender as UIElement;
        if (uie != null && uie.IsMouseCaptured)
        {
            uie.ReleaseMouseCapture();
            UIElement element = e.OriginalSource as UIElement;
            if (element != null && element.InputHitTest(e.GetPosition(element)) != null) element.RaiseEvent(new RoutedEventArgs(Extensions.ClickEvent));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

<TextBlock local:Extensions.Click="TextBlock_Click" Text="Test"/>
Run Code Online (Sandbox Code Playgroud)

编辑:将其更改为使用鼠标捕获而不是存储未充分清除的发件人/来源。剩下的问题是您无法在代码中添加事件 usingUIElement.AddHandler(Extensions.ClickEvent, handler)因为这省略了引发点击事件所需的其他鼠标事件的附件(您需要Extensions.AddClickHandler(object, handler)改用)。