我需要回忆一些数据调用连接到Web服务的方法。
问题:假设我需要根据此远程收集的信息更新标签控件的内容文本。在重新收集所有这些数据之前,我将无法显示标签。
期望:我想先用默认文本显示标签,当我收到此信息时,我想更新标签内容(请不要将此描述视为糟糕的代码,我正在尝试简要介绍我的真实情况)。
我想创建这些方法的可观察序列。然而,这些方法没有相同的签名。例如:
int GetInt() {
return service.GetInt();
}
string GetString() {
return service.GetString();
}
string GetString2 {
return service.GetString2();
}
这些方法不是async
的。
是否可以创建这些方法的可观察序列?
我该如何创建它?
然而,哪个是实现我的目标的最佳选择?
创建自定义可观察序列可以使用 Observable.Create 来实现。使用您的要求的示例如下所示:
private int GetInt()
{
Thread.Sleep(1000);
return 1;
}
private string GetString()
{
Thread.Sleep(1000);
return "Hello";
}
private string GetString2()
{
Thread.Sleep(2000);
return "World!";
}
private IObservable<string> RetrieveContent()
{
return Observable.Create<string>(
observer =>
{
observer.OnNext("Default Text");
int value = GetInt();
observer.OnNext($"Got value {value}. Getting string...");
string string1 = GetString();
observer.OnNext($"Got string {string1}. Getting second string...");
string string2 = GetString2();
observer.OnNext(string2);
observer.OnCompleted();
return Disposable.Empty;
}
);
}
请注意我是如何通过在每个 GetXXX 方法中引入Thread.Sleep
调用来模拟网络延迟的。为了确保您的 UI 在订阅此可观察量时不会挂起,您应该按如下方式订阅:
IDisposable subscription = RetrieveContent()
.SubscribeOn(TaskPoolScheduler.Default)
.ObserveOn(DispatcherScheduler.Current)
.Subscribe(text => Label = text);
此代码使用 .SubscribeOn(TaskPoolScheduler.Default)
扩展方法使用 TaskPool 线程启动可观察序列,并将被调用 Thread.Sleep 阻止,但由于这不是 UI 线程,因此 UI 将保持响应。然后,为了确保我们更新 UI 线程上的 UI,我们使用".ObserveOn(DispatcherScheduler.Current)",在设置 (数据绑定) Label
属性之前调用对 UI 线程的更新。
希望这就是您要找的,但如果没有,请发表评论,我会尽力进一步提供帮助。
我会考虑为您的服务创建一个包装类,以将值公开为单独的可观察量。
因此,从服务接口开始:
public interface IService
{
int GetInt();
string GetString();
string GetString2();
}
。然后你写ServiceWrapper
:
public class ServiceWrapper : IService
{
private IService service;
private Subject<int> subjectGetInt = new Subject<int>();
private Subject<string> subjectGetString = new Subject<string>();
private Subject<string> subjectGetString2 = new Subject<string>();
public ServiceWrapper(IService service)
{
this.service = service;
}
public int GetInt()
{
var value = service.GetInt();
this.subjectGetInt.OnNext(value);
return value;
}
public IObservable<int> GetInts()
{
return this.subjectGetInt.AsObservable();
}
public string GetString()
{
var value = service.GetString();
this.subjectGetString.OnNext(value);
return value;
}
public IObservable<string> GetStrings()
{
return this.subjectGetString.AsObservable();
}
public string GetString2()
{
var value = service.GetString2();
this.subjectGetString2.OnNext(value);
return value;
}
public IObservable<string> GetString2s()
{
return this.subjectGetString2.AsObservable();
}
}
现在,假设您当前的服务称为 Service
,您将编写以下代码来设置内容:
IService service = new Service();
ServiceWrapper wrapped = new ServiceWrapper(service); // Still an `IService`
var subscription =
Observable
.Merge(
wrapped.GetInts().Select(x => x.ToString()),
wrapped.GetStrings(),
wrapped.GetString2s())
.Subscribe(x => label.Text = x);
IService wrappedService = wrapped;
现在将wrappedService
而不是service
传递给您的代码。它仍在调用底层service
代码,因此无需重写,但您仍然可以获得所需的可观察量。
这实际上是一组四个装饰器模式。