在 Windows Phone 8 中具有按钮点击并按住事件的 Rx

本文关键字:事件 Rx 按钮 Phone Windows | 更新日期: 2023-09-27 18:21:57

我有一个简单的Windows Phone 8应用程序,带有一个按钮和一个文本框。如何将反应式扩展用于按钮点击并按住事件以更改文本框文本?

void AttachRx()
    {
IScheduler cs = new DispatcherScheduler(Deployment.Current.Dispatcher);
        Observable.FromEvent<System.Windows.Input.KeyEventArgs>(btn, "Tap").Throttle(TimeSpan.FromSeconds(.5), cs)
            .Do(a => ChangeText()).Subscribe();
    }

错误信息:

{System.InvalidOperationException:事件委托的形式必须是 void Handler(object, T(,其中 T : EventArgs。 at Microsoft.Phone.Reactive.Observable.FromEvent[TEventArgs](Object target, String eventName( at PhoneApp4.MainPage.AttachRx(( 在PhoneApp4.MainPage..ctor((}

在 Windows Phone 8 中具有按钮点击并按住事件的 Rx

这里有几个问题需要解决。

报告的错误特别指出您尝试添加到 Tap 事件的委托不兼容 - 这是有道理的,因为我不认为 Tap 事件的有效负载KeyEventArgs(我认为它是GestureEventArgs(?您可能最好使用下面示例中使用的Observable.FromEventPattern。这更容易,因为您可以推断EventArgs类型。

警告 - 由于我目前笔记本电脑上只有 WP8.1 SDK,所以我只有与 Tap 不同的 Win RT Tapped 事件,所以我刚刚阅读了Tap上的文档,而不是运行下面的示例。

假设一个名为 btnButton和一个名为 txt 的TextBox以及获取要设置的文本的函数string GetText(),请执行以下操作:

Observable.FromEventPattern<GestureEventArgs>(btn, "Tap")
    .Throttle(TimeSpan.FromSeconds(0.5))
    .Select(_ => GetText())
    .ObserveOnDispatcher()
    .Subscribe(x => this.txt.Text = x);

请注意以下几点:

  • 当标准 .NET 事件可用时,请使用FromEventPattern - 它更适合于此 FromEvent 真正存在以处理不符合委托。
  • 不要像这样使用Do。它作为一个副作用,并不是真正的惯用函数式反应式编程。这样做通常还可能导致更复杂的查询中出现意外问题。相反,使用Select将输入事件投影到所需的结果。
  • 不要在调度程序上运行Throttle - 使用默认调度程序(或使用 .Throttle(TimeSpan.FromSeconds(0.5), Scheduler.Default) 参数化可测试性。您不需要在调度程序上运行 Throttle - 最好在后台运行。您只想在准备好更新 UI 时转移到调度程序。
  • 如果导入 nuget 包rx-xaml则可以使用 ObservableOnDispatcher 获取当前调度程序。虽然,为了可测试性,您可能希望使用 ObserveOn 的重载(也在 rx-xaml 中(,它采用依赖对象,例如您正在运行的页面 - 例如 ObserveOn(this)例如,如果您在页面代码隐藏中设置订阅,页面本身就可以了。

上面的示例假定GetText是同步的。如果需要进行异步调用以获取要显示的文本,请使用以下模式(假设GetText具有Task<String>返回类型(:

Observable.FromEventPattern<GestureEventArgs>(btn, "Tap")
          .Throttle(TimeSpan.FromSeconds(0.5), Scheduler.Default)
          .Select(_ => Observable.FromAsync(GetText)
                                 .ObserveOn(this))
          .Switch()
          .Subscribe(x => this.Name.Text = x);

请注意ObserveOnSelect内看起来很奇怪。简要解释其原因非常复杂(我不确定它与这个问题的相关性如何(,但基本上它避免了竞争条件,即如果对较早事件的长时间运行的异步 GetText 调用可能会由于稍后的事件而覆盖短运行调用的结果。