c# - 使用Reactive Extensions模拟UIElement的点击

标签 c# wpf system.reactive

在 WPF 中,我希望能够使用具有反应式扩展的鼠标事件来为 UIElement 创建一个类似于 Click 事件的可观察对象。有很多使用它来创建拖放行为的示例,但我找不到任何只需简单点击的东西。

我预计它将涉及 MouseLeftButtonDown、MouseLeftButtonUp、MouseLeave 和 MouseEnter 上的可观察量。但我不确定需要使用 Merge、SelectMany、TakeUntil 或 TakeWhile 的哪种组合。在尝试将其全部包装在扩展中时,这是我到目前为止所得到的:

public static IDisposable GetClick(this UIElement item, Action clickAction)
        {
            var obs1 = Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
                    h => (s, e) => h(s, e),
                    h => item.MouseLeftButtonDown += h,
                    h => item.MouseLeftButtonDown -= h);

            var obs2 = Observable.FromEventPattern<MouseButtonEventHandler, MouseButtonEventArgs>(
                    h => (s, e) => h(s, e),
                    h => item.MouseLeftButtonUp += h,
                    h => item.MouseLeftButtonUp -= h);

            var obs3 = Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(
                    h => (s, e) => h(s, e),
                    h => item.MouseLeave += h,
                    h => item.MouseLeave -= h);

            var obs4 = Observable.FromEventPattern<MouseEventHandler, MouseEventArgs>(
                    h => (s, e) => h(s, e),
                    h => item.MouseEnter += h,
                    h => item.MouseEnter -= h);

             var finalObs = ???

             return finalObs.Subscribe(x => clickAction.Invoke());

}

最佳答案

以下似乎可行,但我怀疑可以用更简洁的方式来实现。

var click = mouseEnter
    .SelectMany(_ => mouseDown.TakeUntil(mouseLeave))
    .SelectMany(_ => mouseUp.TakeUntil(mouseLeave).Take(1));

我已将 finalObs 重命名为 clickobs1 重命名为 mouseDownobs2 > 到 mouseUp...

编辑:添加了 Take(1) 以修复 Enigmativity 指出的缺陷

编辑(2):

这是我更喜欢的另一个解决方案。

您需要将 .Select(_ => "U") 添加到 mouseUp 的定义中,.Select(_ => "D")鼠标按下...

var click = Observable.Merge(mouseDown, mouseUp, mouseLeave, mouseEnter)
    .Scan((s, c) => c == "L" ? "" : s + c)  // Create a string of the events, reset on mouseLeave
    .Where(s => s.Length >= 2 && s.Substring(s.Length - 2) == "DU");

经过思考,在用户将鼠标放在项目上,然后移到项目外部,然后向后移动并抬起鼠标的情况下,不可能获得完全正确的行为。这是因为当鼠标不在该项目上方时,您不会获得鼠标向上移动的信息,因此您无法确定它们是否没有在项目外时向上移动鼠标,然后向下移动鼠标。

关于c# - 使用Reactive Extensions模拟UIElement的点击,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22490646/

相关文章:

c# - ReactiveExtension 按需调用异步代码

refactoring - 任务 ToObservable 错误处理

java - 如何使不同子类的实例具有其公共(public)父类的相同实例?

c# - Net Core 3.0 中没有 UseDatabaseErrorPage() 扩展方法

c# - 将 RGB 字节转换为 HSL 并返回?

wpf - 在 WPF 中自动调整 ReportViewer 的大小?

c# - WPF数据绑定(bind)不更新

c# - WCF 服务应用程序使用 WebGet 返回 404

c# - 在 .NET 中寻找简单的规则引擎库

c# - Observable 读取流直到它结束或出现错误