反应性扩展的可观察模式

本文关键字:观察 模式 扩展 | 更新日期: 2023-09-27 18:11:07

我试图理解下面的代码试图使用响应式扩展

 IObservable<string> textChangedObservable =
            Observable.FromEventPattern<TextChangedEventArgs>(searchScrip, "TextChanged")
                .Select(evt => ((TextBox) sender).Text);
 textChangedObservable.Subscribe(OnNext, OnCompleted);
private void OnNext(string s)
    {
        System.Diagnostics.Debug.Print("OnNext " + s + "'n");
    }
    private void OnCompleted()
    {
        System.Diagnostics.Debug.Print("OnCompleted " + "'n");
    }

如果我在输入框中输入SEARC,输出看起来是

  • OnNext SE
  • OnNext SEA
  • OnNext海
  • OnNext烤焦的
  • OnNext SEAR
  • OnNext烤焦的
  • OnNext SEARC
  • OnNext search
  • OnNext search
  • OnNext SEARC

    1. 为什么"S"不触发OnNext?
    2. 为什么OnCompleted从未被调用?
  • 为什么OnNext在第n个字符上调用n-1次?

反应性扩展的可观察模式

看来你正在订阅searchScrip_TextChanged处理程序中的可观察对象。

这意味着searchScrip_TextChanged第一次被调用S已经发生在之前,你已经连接了可观察对象。所以它当然不会开火。

但是现在S被击中了,你有一个订阅,所以当E被键入时,你得到一个SE。但是,由于searchScrip_TextChanged处理程序也被E调用,现在你的可观察对象有两个订阅。

所以当输入A时,你得到两个SEA,因为你有两个可观察对象。但是searchScrip_TextChanged又被称为A,所以现在你有三个可观测对象。

等等,等等,等等。

事件不会自动完成。您需要手动解除订阅以结束订阅。这应该是有意义的,因为这是你必须对你想要停止的普通事件处理程序做的。

你应该在加载表单时创建你的可观察对象,这样它就会被创建一次。

应该是这样的:

IObservable<string> textChangedObservable =
        Observable.FromEventPattern<TextChangedEventArgs>(searchScrip, "TextChanged")
            .Select(evt => searchScrip.Text);
IDisposable subscription =
    textChangedObservable
        .Subscribe(
            s => Debug.Print("OnNext " + s + "'n"),
            s => Debug.Print("OnCompleted'n"));

这里的问题实际上与Rx无关。

1:为什么"S"不触发OnNext?

因为您订阅的TextChanged事件没有在第一个s上触发

2:为什么OnCompleted从未被调用?

当你将。net事件包装为IObservable<T>时,你永远不会得到OnErrorOnCompleted通知。对于。net事件,没有错误或完成的概念。

如果有两个事件,一个用于值,一个用于完成,你可以像这样组合它们:

var values = Observable.FromEvent(...);
var completion = Observable.FromEvent(...);
var query = values.TakeUntil(completion);

现在query将产生一个适当的OnCompleted通知。

3:为什么OnNext在第n个字符上调用n-1次?

因为您订阅的TextChanged事件以这种方式触发。正如@Kari-Antti所指出的,这可能是使用"路由属性"事件的副作用。

也许是因为你使用了RoutedPropertyChangedEventArgs?

如果你使用PropertyChangedEventHandler呢?

Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
                h => yourModel.propertyChanged += h,
                h => yourModel.propertyChanged -= h)
            .Where(x => x.EventArgs.PropertyName = "your_property_name");
    }