使用reative扩展在linqpad中恢复数据库时显示进度

我有以下C#代码。

var databaseRestore = new Microsoft.SqlServer.Management.Smo.Restore(); //databaseRestore.PercentComplete += CompletionStatusInPercent; //databaseRestore.PercentCompleteNotification = 10; //databaseRestore.Complete += Restore_Completed; ... var complete = Observable .FromEventPattern(databaseRestore, "Complete") .Select(x=>x.EventArgs as ServerMessageEventArgs) .Select(x=>x.Error.Message) .Take(1) .DumpLive("Complete"); var percentComplete = Observable .FromEventPattern(databaseRestore, "PercentComplete") .Select(x=>x.EventArgs as PercentCompleteEventArgs) .Select(x=>x.Percent) .TakeUntil(complete) .DumpLive("PercentComplete"); ... databaseRestore.SqlRestore(server); 

如果我运行它,首先来自处理程序的输出(如果我取消注释它们)。

然后,首先,Linqpad显示“Live Observables”结果选项卡

  1. “完整”可观察,已完成并带有最终结果消息。
  2. “PercentComplete”,仍在等待“ – ”(但没有条目?)

我想要的只是远离使用react nativeextenxions的事件。 首先应该通过实际进度更新“PercentComplete”可观察量。 然后使用最终消息“完成”。

问题是:如何正确设置可观察量?

我猜这是DumpLive()在主线程上使用Dispatcher的错误。

您是在主线程上运行数据库还原,还是阻止主线程等待完成信号?

我尝试了一下并在后台线程上运行了一个带有DumpLive()的Observable – 如果主线程被阻塞(例如使用Wait或Thread.Sleep),UI没有更新。

即使它在不同的线程上,似乎DumpLive()只能更新主线程上的UI。 我猜它需要在与主线程关联的Dispatcher上呈现更新。

使用DumpLive时,LINQPad不会终止执行,直到observable完成,所以如果主线程上有任何阻塞代码,请将其删除,然后查看它是否有效。

这是我的实验代码。 只要在下面的示例中添加DumpLive()子句,您就会看到阻塞行为:

 void Main() { Task.Run(() => { var progressor = new Progressor(); var complete = Observable .FromEventPattern( h => progressor.Complete += h, h => progressor.Complete -= h) .Select(_ => "Complete") .Take(1); // append this to see blocking //.DumpLive(); complete.Subscribe(Console.WriteLine); var percentComplete = Observable .FromEventPattern( h => progressor.PercentComplete += h, h => progressor.PercentComplete -= h) .TakeUntil(complete) .Select(i => "PercentComplete " + i.EventArgs.PercentComplete); // append this to see blocking // .DumpLive(); percentComplete.Subscribe(Console.WriteLine); }); Thread.Sleep(5000); } public class Progressor { public Progressor() { Observable.Interval(TimeSpan.FromSeconds(1)).Take(10) .Subscribe( i => RaisePercentComplete(((int)i+1) * 10), () => RaiseComplete()); } private void RaiseComplete() { var temp = Complete; if(temp != null) { temp(this, EventArgs.Empty); } } private void RaisePercentComplete(int percent) { var temp = PercentComplete; if(temp != null) { temp(this, new PercentCompleteEventArgs(percent)); } } public event EventHandler Complete; public event EventHandler PercentComplete; } public class PercentCompleteEventArgs : EventArgs { public int PercentComplete { get; private set; } public PercentCompleteEventArgs(int percent) { PercentComplete = percent; } } 

LINQPad的DumpLive方法呈现使用WPF,因此如果主线程被阻止,它将无法工作。

您可以改为使用HTML编写自己的DumpLive版本。 这将更慢(因为它必须在每次observable发布值时更新HTML DOM),但无论主线程是否被阻止它都会起作用。

这是代码:

 IDisposable DumpLatest (IObservable obs) { var dc = new DumpContainer ().Dump(); var extensionToken = Util.GetQueryLifeExtensionToken(); return obs.Subscribe ( value => dc.Content = value, ex => { dc.Content = ex; extensionToken.Dispose(); }, () => extensionToken.Dispose()); } 

如果您在“ 我的扩展”中将其定义为扩展方法,则可以在需要时随时调用它。