Browse Source

Allow creating an IObservable<> from a function that invokes a callback and signals termination using a Task.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
9d7bdd0cf8
  1. 7
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpContextActionDoozer.cs
  2. 6
      src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.cs
  3. 14
      src/Main/Base/Project/Src/Gui/IProgressMonitor.cs
  4. 17
      src/Main/Base/Project/Src/Gui/ProgressCollector.cs
  5. 55
      src/Main/Base/Project/Src/Util/ReactiveExtensions.cs

7
src/AddIns/BackendBindings/CSharpBinding/Project/Src/CSharpContextActionDoozer.cs

@ -59,9 +59,9 @@ namespace CSharpBinding
return Task.FromResult(false); return Task.FromResult(false);
return Task.Run( return Task.Run(
async delegate { async delegate {
var parseInfo = (await context.GetParseInformationAsync().ConfigureAwait(false)) as CSharpFullParseInformation; // var parseInfo = (await context.GetParseInformationAsync().ConfigureAwait(false)) as CSharpFullParseInformation;
if (parseInfo == null) // if (parseInfo == null)
return false; // return false;
lock (this) { lock (this) {
if (!contextActionCreated) { if (!contextActionCreated) {
contextActionCreated = true; contextActionCreated = true;
@ -71,6 +71,7 @@ namespace CSharpBinding
if (contextAction == null) if (contextAction == null)
return false; return false;
CSharpAstResolver resolver = await context.GetAstResolverAsync().ConfigureAwait(false); CSharpAstResolver resolver = await context.GetAstResolverAsync().ConfigureAwait(false);
//var refactoringContext = new SDRefactoringContext(context, resolver, cancellationToken);
return true; return true;
}, cancellationToken); }, cancellationToken);
} }

6
src/Main/Base/Project/Src/Gui/Dialogs/AsynchronousWaitDialog.cs

@ -311,6 +311,12 @@ namespace ICSharpCode.SharpDevelop.Gui
return collector.ProgressMonitor.CreateSubTask(workAmount); return collector.ProgressMonitor.CreateSubTask(workAmount);
} }
/// <inheritdoc/>
public IProgressMonitor CreateSubTask(double workAmount, CancellationToken cancellationToken)
{
return collector.ProgressMonitor.CreateSubTask(workAmount, cancellationToken);
}
public void Dispose() public void Dispose()
{ {
collector.ProgressMonitor.Dispose(); collector.ProgressMonitor.Dispose();

14
src/Main/Base/Project/Src/Gui/IProgressMonitor.cs

@ -34,6 +34,15 @@ namespace ICSharpCode.SharpDevelop.Gui
/// Multiple child progress monitors can be used at once; even concurrently on multiple threads.</returns> /// Multiple child progress monitors can be used at once; even concurrently on multiple threads.</returns>
IProgressMonitor CreateSubTask(double workAmount); IProgressMonitor CreateSubTask(double workAmount);
/// <summary>
/// Creates a nested task.
/// </summary>
/// <param name="workAmount">The amount of work this sub-task performs in relation to the work of this task.
/// That means, this parameter is used as a scaling factor for work performed within the subtask.</param>
/// <returns>A new progress monitor representing the sub-task.
/// Multiple child progress monitors can be used at once; even concurrently on multiple threads.</returns>
IProgressMonitor CreateSubTask(double workAmount, CancellationToken cancellationToken);
/// <summary> /// <summary>
/// Gets/Sets the name to show while the task is active. /// Gets/Sets the name to show while the task is active.
/// </summary> /// </summary>
@ -101,6 +110,11 @@ namespace ICSharpCode.SharpDevelop.Gui
return new DummyProgressMonitor() { CancellationToken = this.CancellationToken }; return new DummyProgressMonitor() { CancellationToken = this.CancellationToken };
} }
public IProgressMonitor CreateSubTask(double workAmount, CancellationToken cancellationToken)
{
return new DummyProgressMonitor() { CancellationToken = cancellationToken };
}
public void Dispose() public void Dispose()
{ {
} }

17
src/Main/Base/Project/Src/Gui/ProgressCollector.cs

@ -15,7 +15,6 @@ namespace ICSharpCode.SharpDevelop.Gui
public sealed class ProgressCollector : INotifyPropertyChanged public sealed class ProgressCollector : INotifyPropertyChanged
{ {
readonly ISynchronizeInvoke eventThread; readonly ISynchronizeInvoke eventThread;
readonly CancellationToken cancellationToken;
readonly MonitorImpl root; readonly MonitorImpl root;
readonly LinkedList<string> namedMonitors = new LinkedList<string>(); readonly LinkedList<string> namedMonitors = new LinkedList<string>();
readonly object updateLock = new object(); readonly object updateLock = new object();
@ -31,8 +30,7 @@ namespace ICSharpCode.SharpDevelop.Gui
if (eventThread == null) if (eventThread == null)
throw new ArgumentNullException("eventThread"); throw new ArgumentNullException("eventThread");
this.eventThread = eventThread; this.eventThread = eventThread;
this.cancellationToken = cancellationToken; this.root = new MonitorImpl(this, null, 1, cancellationToken);
this.root = new MonitorImpl(this, null, 1);
} }
public event EventHandler ProgressMonitorDisposed; public event EventHandler ProgressMonitorDisposed;
@ -213,16 +211,18 @@ namespace ICSharpCode.SharpDevelop.Gui
readonly ProgressCollector collector; readonly ProgressCollector collector;
readonly MonitorImpl parent; readonly MonitorImpl parent;
readonly double scaleFactor; readonly double scaleFactor;
readonly CancellationToken cancellationToken;
LinkedListNode<string> nameEntry; LinkedListNode<string> nameEntry;
double currentProgress; double currentProgress;
OperationStatus localStatus, currentStatus; OperationStatus localStatus, currentStatus;
int childrenWithWarnings, childrenWithErrors; int childrenWithWarnings, childrenWithErrors;
public MonitorImpl(ProgressCollector collector, MonitorImpl parent, double scaleFactor) public MonitorImpl(ProgressCollector collector, MonitorImpl parent, double scaleFactor, CancellationToken cancellationToken)
{ {
this.collector = collector; this.collector = collector;
this.parent = parent; this.parent = parent;
this.scaleFactor = scaleFactor; this.scaleFactor = scaleFactor;
this.cancellationToken = cancellationToken;
} }
public bool ShowingDialog { public bool ShowingDialog {
@ -254,7 +254,7 @@ namespace ICSharpCode.SharpDevelop.Gui
} }
public CancellationToken CancellationToken { public CancellationToken CancellationToken {
get { return collector.cancellationToken; } get { return cancellationToken; }
} }
public double Progress { public double Progress {
@ -317,7 +317,12 @@ namespace ICSharpCode.SharpDevelop.Gui
public IProgressMonitor CreateSubTask(double workAmount) public IProgressMonitor CreateSubTask(double workAmount)
{ {
return new MonitorImpl(collector, this, workAmount); return new MonitorImpl(collector, this, workAmount, cancellationToken);
}
public IProgressMonitor CreateSubTask(double workAmount, CancellationToken cancellationToken)
{
return new MonitorImpl(collector, this, workAmount, cancellationToken);
} }
public void Dispose() public void Dispose()

55
src/Main/Base/Project/Src/Util/ReactiveExtensions.cs

@ -5,8 +5,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.SharpDevelop.Gui; using ICSharpCode.SharpDevelop.Gui;
namespace ICSharpCode.SharpDevelop namespace ICSharpCode.SharpDevelop
@ -29,6 +29,59 @@ namespace ICSharpCode.SharpDevelop
); );
} }
public static IObservable<T> CreateObservable<T>(Func<CancellationToken, Action<T>, Task> func)
{
return new AnonymousObservable<T>(observer => new TaskToObserverSubscription<T>(func, observer));
}
public static IObservable<T> CreateObservable<T>(Func<IProgressMonitor, Action<T>, Task> func, IProgressMonitor progressMonitor)
{
return new AnonymousObservable<T>(observer => new TaskToObserverSubscription<T>(func, progressMonitor, observer));
}
sealed class TaskToObserverSubscription<T> : IDisposable
{
readonly CancellationTokenSource cts = new CancellationTokenSource();
readonly object syncLock = new object();
readonly IObserver<T> observer;
readonly IProgressMonitor childProgressMonitor;
public TaskToObserverSubscription(Func<CancellationToken, Action<T>, Task> func, IObserver<T> observer)
{
this.observer = observer;
func(cts.Token, Callback).ContinueWith(TaskCompleted);
}
public TaskToObserverSubscription(Func<IProgressMonitor, Action<T>, Task> func, IProgressMonitor progressMonitor, IObserver<T> observer)
{
this.observer = observer;
this.childProgressMonitor = progressMonitor.CreateSubTask(1, cts.Token);
func(childProgressMonitor, Callback).ContinueWith(TaskCompleted);
}
void Callback(T item)
{
// Needs lock because callbacks may be called in parallel, but OnNext may not.
lock (syncLock)
observer.OnNext(item);
}
void TaskCompleted(Task task)
{
if (childProgressMonitor != null)
childProgressMonitor.Dispose();
if (task.Exception != null)
observer.OnError(task.Exception.InnerExceptions[0]);
else
observer.OnCompleted();
}
public void Dispose()
{
cts.Cancel();
}
}
public static IDisposable Subscribe<T>(this IObservable<T> source, Action<T> onNext, Action<Exception> onError, Action onCompleted) public static IDisposable Subscribe<T>(this IObservable<T> source, Action<T> onNext, Action<Exception> onError, Action onCompleted)
{ {
return source.Subscribe(new AnonymousObserver<T>(onNext, onError, onCompleted)); return source.Subscribe(new AnonymousObserver<T>(onNext, onError, onCompleted));

Loading…
Cancel
Save