使用 Rx.Net 的搜索实现
Search implementation using Rx.Net
我正在使用 C# 中的 Rx 创建一个搜索页面实现。我创建了一个通用搜索方法来搜索关键字并在 UI 上添加结果列表。下面是代码:
通用搜索方法:
public static IObservable<TResult> GetSearchObservable<TInput, TResult>(INotifyPropertyChanged propertyChanged,
string propertyName, TInput propertyValue, Func<TInput, TResult> searchFunc)
{
// Text change event stream
var searchTextChanged = Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
ev => propertyChanged.PropertyChanged += ev,
ev => propertyChanged.PropertyChanged -= ev
)
.Where(ev => ev.EventArgs.PropertyName == propertyName);
// Transform the event stream into a stream of strings (the input values)
var inputStringStream = searchTextChanged.Throttle(TimeSpan.FromMilliseconds(500))
.Select(arg => propertyValue);
// Setup an Observer for the search operation
var search = Observable.ToAsync<TInput, TResult>(searchFunc);
// Chain the input event stream and the search stream, cancelling searches when input is received
var results = from searchTerm in inputStringStream
from result in search(propertyValue).TakeUntil(inputStringStream)
select result;
return results;
}
搜索通用方法的使用:
var rand = new Random();
SearchObservable.GetSearchObservable<string, string>(this, "SearchString", SearchString, search =>
{
Task.WaitAll(Task.Delay(500));
return SearchString;
})
.ObserveOnDispatcher()
.Subscribe(rese =>
{
LstItems.Clear();
LstItems.Add(SearchString);
// Heavy operation lots of item to add to UI
for(int i = 0; i < 200000; i++)
{
LstItems.Add(rand.Next(100, 100000).ToString());
}
Result = rese;
});
此代码中有 2 个问题需要帮助解决:
在通用方法行中传递的搜索关键字 from result in search(propertyValue).TakeUntil(inputStringStream)
值始终为空,因为 propertyValue 是字符串类型,因此作为值传递到方法中。如何在搜索方法中发送更新值?
当对 Subscribe 方法进行繁重的 UI 操作时,例如添加大量随机数的示例。当重复执行搜索时,这会导致问题。最终 UI 块。我该如何解决这个问题?
对于第 2 点,有没有办法取消之前的 UI 操作并 运行 一个新的操作。这只是一个想法。但需要一些建议来解决这些问题。
- 您可以传递一个读取 属性 值的函数,即您的方法应该接受
Func<TInput> propertyValueGetter
. 而不是 TInput propertyValue
您还可以使用 ReactiveUI 库。在这种情况下,您的代码将如下所示:
this.WhenAnyValue(vm => vm.SearchString)
.Throttle(TimeSpan.FromMilliseconds(500))
.InvokeCommand(DoSearchString);
DoSearchString = ReactiveCommand.CreateAsyncTask(_ => {
return searchService.Search(SearchString);
});
DoSearchString.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(result => {
LstItems.Add(result);
})
- 我认为这个问题没有通用的答案。在 TaskPool 上做尽可能多的事情,当你的数据准备好显示时,切换到 UI 线程和
ObserveOn
。在您的情况下,您也许可以分批插入项目,而不是一次全部插入。
我正在使用 C# 中的 Rx 创建一个搜索页面实现。我创建了一个通用搜索方法来搜索关键字并在 UI 上添加结果列表。下面是代码:
通用搜索方法:
public static IObservable<TResult> GetSearchObservable<TInput, TResult>(INotifyPropertyChanged propertyChanged,
string propertyName, TInput propertyValue, Func<TInput, TResult> searchFunc)
{
// Text change event stream
var searchTextChanged = Observable.FromEventPattern<PropertyChangedEventHandler, PropertyChangedEventArgs>(
ev => propertyChanged.PropertyChanged += ev,
ev => propertyChanged.PropertyChanged -= ev
)
.Where(ev => ev.EventArgs.PropertyName == propertyName);
// Transform the event stream into a stream of strings (the input values)
var inputStringStream = searchTextChanged.Throttle(TimeSpan.FromMilliseconds(500))
.Select(arg => propertyValue);
// Setup an Observer for the search operation
var search = Observable.ToAsync<TInput, TResult>(searchFunc);
// Chain the input event stream and the search stream, cancelling searches when input is received
var results = from searchTerm in inputStringStream
from result in search(propertyValue).TakeUntil(inputStringStream)
select result;
return results;
}
搜索通用方法的使用:
var rand = new Random();
SearchObservable.GetSearchObservable<string, string>(this, "SearchString", SearchString, search =>
{
Task.WaitAll(Task.Delay(500));
return SearchString;
})
.ObserveOnDispatcher()
.Subscribe(rese =>
{
LstItems.Clear();
LstItems.Add(SearchString);
// Heavy operation lots of item to add to UI
for(int i = 0; i < 200000; i++)
{
LstItems.Add(rand.Next(100, 100000).ToString());
}
Result = rese;
});
此代码中有 2 个问题需要帮助解决:
在通用方法行中传递的搜索关键字
from result in search(propertyValue).TakeUntil(inputStringStream)
值始终为空,因为 propertyValue 是字符串类型,因此作为值传递到方法中。如何在搜索方法中发送更新值?当对 Subscribe 方法进行繁重的 UI 操作时,例如添加大量随机数的示例。当重复执行搜索时,这会导致问题。最终 UI 块。我该如何解决这个问题?
对于第 2 点,有没有办法取消之前的 UI 操作并 运行 一个新的操作。这只是一个想法。但需要一些建议来解决这些问题。
- 您可以传递一个读取 属性 值的函数,即您的方法应该接受
Func<TInput> propertyValueGetter
. 而不是
TInput propertyValue
您还可以使用 ReactiveUI 库。在这种情况下,您的代码将如下所示:
this.WhenAnyValue(vm => vm.SearchString)
.Throttle(TimeSpan.FromMilliseconds(500))
.InvokeCommand(DoSearchString);
DoSearchString = ReactiveCommand.CreateAsyncTask(_ => {
return searchService.Search(SearchString);
});
DoSearchString.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe(result => {
LstItems.Add(result);
})
- 我认为这个问题没有通用的答案。在 TaskPool 上做尽可能多的事情,当你的数据准备好显示时,切换到 UI 线程和
ObserveOn
。在您的情况下,您也许可以分批插入项目,而不是一次全部插入。