我试图理解下面的代码试图使用响应式扩展
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
- 为什么"S"不触发OnNext? 为什么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("OnCompletedn"));
这里的问题实际上与Rx无关。
1:为什么"S"不触发OnNext?
因为您订阅的TextChanged
事件没有在第一个s上触发
2:为什么OnCompleted从未被调用?
当你将。net事件包装为IObservable<T>
时,你永远不会得到OnError
或OnCompleted
通知。对于。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");
}