public WebViewAwarePage() : base() { this.isNewInstance = true; this.isDomReady = false; domReady = new TaskCompletionSource<bool>(); progress = new SystemTrayProgressToken(); }
public ArticlePage() { InitializeComponent(); progress = new SystemTrayProgressToken(); mainDataModel = App.Main; VisualStateManager.GoToState(this, "Normal", false); }
public static IRequestProgressObservable <TItem, TResponse> RequestProgress <TResponse, TItem>( this ILanguageProtocolProxy requestRouter, IPartialItemRequest <TResponse, TItem> @params, Func <TItem, TResponse> factory, CancellationToken cancellationToken = default ) { var resultToken = new ProgressToken(Guid.NewGuid().ToString()); @params.PartialResultToken = resultToken; return(requestRouter.ProgressManager.MonitorUntil(@params, factory, cancellationToken)); }
public async Task Should_Support_Creating_Work_Done_From_Sever_To_Client() { var(client, server) = await Initialize(ConfigureClient, ConfigureServer); var token = new ProgressToken(Guid.NewGuid().ToString()); var data = new List <WorkDoneProgress>(); using var workDoneObservable = client.WorkDoneManager.Monitor(token); workDoneObservable.Subscribe(x => data.Add(x)); using var workDoneObserver = await server.WorkDoneManager.Create(token, new WorkDoneProgressBegin () { Cancellable = true, Message = "Begin", Percentage = 0, Title = "Work is pending" }, onComplete : () => new WorkDoneProgressEnd() { Message = "End" }); workDoneObserver.OnNext(new WorkDoneProgressReport() { Percentage = 10, Message = "Report 1" }); workDoneObserver.OnNext(new WorkDoneProgressReport() { Percentage = 20, Message = "Report 2" }); workDoneObserver.OnNext(new WorkDoneProgressReport() { Percentage = 30, Message = "Report 3" }); workDoneObserver.OnNext(new WorkDoneProgressReport() { Percentage = 40, Message = "Report 4" }); workDoneObserver.OnCompleted(); await SettleNext(); var results = data.Select(z => z switch { WorkDoneProgressBegin begin => begin.Message, WorkDoneProgressReport begin => begin.Message, WorkDoneProgressEnd begin => begin.Message, });
public IProgressObserver <T> For <T>(ProgressToken token, CancellationToken cancellationToken) { if (_activeObservers.TryGetValue(token, out var o) && o is IProgressObserver <T> observer) { return(observer); } observer = new ProgressObserver <T>(token, _router, _serializer, cancellationToken, () => _activeObservers.TryRemove(token, out var disposable)); _activeObservers.TryAdd(token, observer); return(observer); }
private static IObserver <T> CreateWorker <T>( ProgressToken token, IResponseRouter router, ISerializer serializer, IDisposable disposable) { return(Observer.Create <T>( value => router.SendProgress(token.Create(value, serializer.JsonSerializer)), error => { disposable.Dispose(); }, disposable.Dispose)); }
public IProgressObservable <T> Monitor <T>(ProgressToken token, Func <JToken, T> factory) { if (_activeObservables.TryGetValue(token, out var o) && o is IProgressObservable <T> observable) { return(observable); } observable = new ProgressObservable <T>(token, factory, () => _activeObservables.TryRemove(token, out var disposable)); _activeObservables.TryAdd(token, observable); return(observable); }
/// <summary> /// Returns a dictionary that maps subVI names of method calls in the source <see cref="DfirRoot"/> to /// the corresponding <see cref="DfirRoot"/> objects. /// </summary> /// <param name="sourceDfirRoot">The parent document that does the method call</param> /// <param name="nameDictionary">The dictionary to fill out with names to dfir maps.</param> /// <param name="compileCancellationToken">The cancellation token</param> /// <param name="progressToken">The progress token</param> /// <param name="host">The composition host</param> /// <returns>The task to wait on</returns> private static async Task GetSubDfirRootsAsync( DfirRoot sourceDfirRoot, IDictionary <ExtendedQualifiedName, DfirRoot> nameDictionary, CompileCancellationToken compileCancellationToken, ProgressToken progressToken, ICompositionHost host) { if (sourceDfirRoot == null) { return; } // Maintain a queue of VIs to visit, and visit each one. var rootsToProcess = new Queue <DfirRoot>(); // Add the top-level VI to the queue so it is visited first. rootsToProcess.Enqueue(sourceDfirRoot); while (rootsToProcess.Count > 0) { DfirRoot root = rootsToProcess.Dequeue(); foreach (MethodCall node in root.BlockDiagram.GetAllNodes().OfType <MethodCall>()) { var specAndQName = new SpecAndQName(node.TargetBuildSpec, node.TargetName); var compiler = host.GetSharedExportedValue <AnyMocCompiler>(); DfirRoot subDfirRoot; try { subDfirRoot = await compiler.GetTargetDfirAsync(specAndQName, compileCancellationToken, progressToken); RemoveDebugPoints(subDfirRoot, compileCancellationToken); } catch { await ShowErrorMessageBoxAsync(host, DfirGenerationErrorMessageBoxText); return; } if (subDfirRoot == null) { continue; } if (nameDictionary.ContainsKey(node.TargetName)) { // If the subVI has already been visited, then don't enqueue it to be visited again. continue; } // The subVI has not been visited. Add the subVI to the queue of VIs to visit. nameDictionary[node.TargetName] = subDfirRoot; rootsToProcess.Enqueue(subDfirRoot); } } }
private async Task <bool> BuildComponentAsync(ComponentConfigurationReference configurationReference) { var progressToken = new ProgressToken(); CancellationTokenSource <CompileCancellationToken> cancellationTokenSource = CompileCancellationToken.CreateNewSource(); using (var buildMonitor = new CommandLineBuildJobMonitor(configurationReference.Configuration, progressToken, cancellationTokenSource)) { bool result = await StartBuildAsync(configurationReference, progressToken, cancellationTokenSource); return(result && await buildMonitor.WaitForBuildToFinishAsync()); } }
public async Task Should_Send_Progress_From_Client_To_Server() { var token = new ProgressToken(Guid.NewGuid().ToString()); using var observer = Server.ProgressManager.For <Data>(token, CancellationToken); var workDoneObservable = Client.ProgressManager.Monitor(token, x => x.ToObject <Data>(Client.Services.GetRequiredService <ISerializer>().JsonSerializer)); var observable = workDoneObservable.Replay(); using var _ = observable.Connect(); observer.OnNext( new Data { Value = "1" } ); observer.OnNext( new Data { Value = "3" } ); observer.OnNext( new Data { Value = "2" } ); observer.OnNext( new Data { Value = "4" } ); observer.OnNext( new Data { Value = "5" } ); observer.OnCompleted(); await Observable.Create <Unit>( innerObserver => new CompositeDisposable() { observable .Take(5) .Select(z => z.Value) .Subscribe(v => innerObserver.OnNext(Unit.Default), innerObserver.OnCompleted), workDoneObservable } ).ToTask(CancellationToken); var data = await observable.Select(z => z.Value).ToArray().ToTask(CancellationToken); data.Should().ContainInOrder(new[] { "1", "3", "2", "4", "5" }); }
private void Render(Stream stream, int width, int height, ParameterBinding rp, ProgressToken token) { // get relative rotation amount var rotXDiff = rp.RotationX - _lastRotX; var rotYDiff = rp.RotationY - _lastRotY; var rotZDiff = rp.RotationZ - _lastRotZ; _lastRotX = rp.RotationX; _lastRotY = rp.RotationY; _lastRotZ = rp.RotationZ; // rotation // get new *relative* world q var rotationDiff = Matrix.RotationYawPitchRoll(rotYDiff, rotXDiff, rotZDiff); // transform world q into local rotation q var fullRotation = _lastRotation*rotationDiff; _lastRotation = fullRotation; // get the world projection matrix fullRotation.Transpose(); // set the camera zoom _scene.Camera.Scale = 1 / rp.Zoom; if (stream.CanWrite) { stream.Position = 0; // generate checkpoints var tenPercent = (width*height)/10; var list = Enumerable.Range(1, 9).Select(i => i*tenPercent).ToList(); int p = 0; for (var y = 0; y < height; y++) { for (var x = 0; x < width; x++) { var color = TraceRay(fullRotation, x, height - y, width, height); stream.WriteByte(color.B); stream.WriteByte(color.G); stream.WriteByte(color.R); stream.WriteByte(color.A); if (token != null && list.Contains(++p)) { token.Value += 10; } } } stream.Flush(); } }
public ProgressObservable(ProgressToken token) { _dataSubject = new ReplaySubject <ProgressEvent>(1); _disposable = new CompositeDisposable { Disposable.Create(_dataSubject.OnCompleted) }; ProgressToken = token; if (_dataSubject is IDisposable disposable) { _disposable.Add(disposable); } }
public static ProgressObserver <T> Create <T>( ProgressToken token, IResponseRouter router, ISerializer serializer, CancellationToken cancellationToken) { var observer = new Subject <WorkDoneProgress>(); var disposable = new CompositeDisposable { observer }; return(new ProgressObserver <T>(token, CreateWorker <T>(token, router, serializer, disposable), CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))); }
public async Task<WriteableBitmap> RenderAsync(int width, int height, ParameterBinding rp, ProgressToken token) { var wb = new WriteableBitmap(width, height); var stream = wb.PixelBuffer.AsStream(); await Task.Run(() => Render(stream, width, height, rp, token)); if (token != null) { token.Value = 100; } return wb; }
void operatMachine(Func <ProgressToken> operation, Machine m, string operationDescription, MachineOperationToken successfulOperations, Logging.MachineControllerEventIds eventId, Logging.MachineControllerEventIds failEventId) { try { ProgressToken t = operation.Invoke(); estimateAndAnnounceTimeForProgressToken(t, successfulOperations); MachineOperation op = new MachineOperation(m, t, operationDescription, eventId); op.Execute(successfulOperations, Logging.MachineControllerEventIds.MachineStartupFailed); } catch (Exception ex) { _log.TraceEvent(TraceEventType.Error, (int)failEventId, "{0} on machine {1} resulted in an error: {2}", operationDescription, m.Name, ex.ToString()); //no rethrow, because we do not want to interrupt the other processes } }
public ProgressObserver( ProgressToken token, IResponseRouter responseRouter, ISerializer serializer, CancellationToken cancellationToken, Action disposal) { _responseRouter = responseRouter; _serializer = serializer; _disposal = disposal; ProgressToken = token; CancellationToken = cancellationToken; _completionSource = new TaskCompletionSource <System.Reactive.Unit>(); }
public ProgressObservable(ProgressToken token, Func <JToken, T> factory, Action disposal) { _factory = factory; _dataSubject = new ReplaySubject <JToken>(1); _disposable = new CompositeDisposable { Disposable.Create(_dataSubject.OnCompleted), Disposable.Create(disposal) }; ProgressToken = token; if (_dataSubject is IDisposable disposable) { _disposable.Add(disposable); } }
public void EstimateTimeProgressCompletedTest() { Mock <IProgress> progressMock = new Mock <IProgress>(); int completed = 0; progressMock.SetupGet(x => x.Completed).Returns(() => completed).Callback(() => completed = 1); _mockedComMachine.Setup(x => x.LaunchVMProcess(It.IsAny <Session>(), It.IsAny <string>(), It.IsAny <string>())).Returns(progressMock.Object); ComMachineProxy machineProxy = new ComMachineProxy(_mockedComMachine.Object); ProgressToken t = machineProxy.Start(); TimeSpan test = t.EstimateRemainingTime(); Assert.AreEqual(TimeSpan.Zero, test); }
public PartialItemsRequestProgressObservable( ISerializer serializer, ProgressToken token, IObservable <TResult> requestResult, Func <IEnumerable <TItem>, TResult> factory, CancellationToken cancellationToken, Action disposal ) { _serializer = serializer; _dataSubject = new ReplaySubject <IEnumerable <TItem> >(int.MaxValue); var request = requestResult .Do( // this should be fine as long as the other side is spec compliant (requests cannot return new results) so this should be null or empty result => _dataSubject.OnNext(result ?? Enumerable.Empty <TItem>()), OnError, OnCompleted ) .Replay(1); _disposable = new CompositeDisposable { request.Connect(), Disposable.Create(disposal) }; _task = _dataSubject .Scan( new List <TItem>(), (acc, data) => { acc.AddRange(data); return(acc); } ) .StartWith(new List <TItem>()) .Select(factory) .ForkJoin(request, (items, result) => items?.Count() > result?.Count() ? items : result) .ToTask(cancellationToken); #pragma warning disable VSTHRD105 #pragma warning disable VSTHRD110 _task.ContinueWith(_ => Dispose()); #pragma warning restore VSTHRD110 #pragma warning restore VSTHRD105 ProgressToken = token; if (_dataSubject is IDisposable disposable) { _disposable.Add(disposable); } }
public void buildMachineTest() { _mockMachineProxy.Setup(x => x.Start()).Returns(new Mock <ProgressToken>().Object).Verifiable(); ServiceMachineBuilder smb = new ServiceMachineBuilder(); smb.MachineListBuilder = _mockMachineProxyListBuilder.Object; Machine m = smb.buildMachine(_mockMachineProxy.Object); ProgressToken t = m.StartAsync(); _mockMachineProxy.VerifyAll(); Assert.IsInstanceOfType(((ServiceAwareMachine)m).ServiceInfoProvider, typeof(DescriptionBasedInfoProvider)); }
/// <summary> /// Constructs an instance of a <see cref="CommandLineBuildJobMonitor"/>. Creates a build job for a component build and /// begins monitoring the job collection for child jobs to be added. /// </summary> /// <param name="componentConfiguration">The <see cref="ComponentConfiguration"/> for the component build being monitored.</param> /// <param name="progressToken">Progress token to create the build job with.</param> /// <param name="cancellationTokenSource">Cancellation token source to create the build job with.</param> public CommandLineBuildJobMonitor( ComponentConfiguration componentConfiguration, ProgressToken progressToken, CancellationTokenSource <CompileCancellationToken> cancellationTokenSource) { _jobFinishedCompletionSource = new TaskCompletionSource <object>(); _jobCollection = componentConfiguration.Host.GetSharedExportedValue <IJobCollection>(); _jobCollection.CollectionChanged += JobCollectionOnCollectionChanged; _rootJob = CreateNewBuildJob(componentConfiguration, cancellationTokenSource, progressToken, _jobCollection); if (_rootJob == null) { throw new CommandLineOperationException(LocalizedStrings.BuildComponentTool_FailToStartBuildErrorMessage); } SubscribeToRootJobFinishedEvent(); }
void estimateAndAnnounceTimeForProgressToken(ProgressToken t, MachineOperationToken successfulOperations) { try { TimeSpan remainingTime = t.EstimateRemainingTime(); _log.TraceEvent(TraceEventType.Verbose, (int)Logging.MachineControllerEventIds.AnnounceRemainingTime, "Remaining time for current operation: {0}", remainingTime.ToString()); announceEstimatedTime(remainingTime); } catch (NotSupportedException) { announceTimeOfLastOperationOrDefault(successfulOperations); } catch (Exception e) { _log.TraceEvent(TraceEventType.Warning, (int)Logging.MachineControllerEventIds.TimeEstimationProblem, "Could not estimate remaining time for Operation: {0}", e.ToString()); announceTimeOfLastOperationOrDefault(successfulOperations); } }
public void EstimateTimeNegativeTimeTest() { Mock <IProgress> progressMock = new Mock <IProgress>(); _mockedComMachine.Setup(x => x.LaunchVMProcess(It.IsAny <Session>(), It.IsAny <string>(), It.IsAny <string>())).Returns(progressMock.Object); progressMock.Setup(x => x.TimeRemaining).Returns(-100); progressMock.SetupGet(x => x.Percent).Returns(40); ComMachineProxy machineProxy = new ComMachineProxy(_mockedComMachine.Object); ProgressToken t = machineProxy.Start(); TimeSpan test = t.EstimateRemainingTime(); Assert.IsTrue(test.CompareTo(TimeSpan.Zero) > 0, "Negative TimeSpan returned"); }
public void EstimateTimeProgressPercentReachedTest() { Mock <IProgress> progressMock = new Mock <IProgress>(); int percent = 0; progressMock.SetupGet(x => x.Percent).Returns(() => (uint)percent).Callback(() => percent++); progressMock.SetupGet(x => x.TimeRemaining).Returns(10); _mockedComMachine.Setup(x => x.LaunchVMProcess(It.IsAny <Session>(), It.IsAny <string>(), It.IsAny <string>())).Returns(progressMock.Object); ComMachineProxy machineProxy = new ComMachineProxy(_mockedComMachine.Object); ProgressToken t = machineProxy.Start(); TimeSpan test = t.EstimateRemainingTime(); Assert.AreEqual(10, test.TotalSeconds); }
public void StartMachineCancelTest() { Mock <IProgress> progressMock = new Mock <IProgress>(); progressMock.SetupGet(x => x.Cancelable).Returns(1); _mockedComMachine.Setup(x => x.LaunchVMProcess(It.IsAny <Session>(), It.IsAny <string>(), It.IsAny <string>())).Returns(progressMock.Object); ComMachineProxy machineProxy = new ComMachineProxy(_mockedComMachine.Object); ProgressToken t = machineProxy.Start(); Assert.IsInstanceOfType(t, typeof(ComMachineProxy.IProgressProgressToken)); t.Cancel(); progressMock.Verify(x => x.Cancel()); }
public void EstimateTimeProgressTimeoutTest() { Mock <IProgress> progressMock = new Mock <IProgress>(); _mockedComMachine.Setup(x => x.LaunchVMProcess(It.IsAny <Session>(), It.IsAny <string>(), It.IsAny <string>())).Returns(progressMock.Object); ComMachineProxy machineProxy = new ComMachineProxy(_mockedComMachine.Object); ProgressToken t = machineProxy.Start(); try { TimeSpan test = t.EstimateRemainingTime(); Assert.Fail("Timeout exception did not occur!"); } catch (TimeoutException) { } }
public static ProgressObserver <WorkDoneProgressReport> CreateWorkDoneProgress( ProgressToken token, IResponseRouter router, ISerializer serializer, WorkDoneProgressBegin begin, Func <Exception, WorkDoneProgressEnd> onError, Func <WorkDoneProgressEnd> onComplete, CancellationToken cancellationToken) { var disposable = new CompositeDisposable(); var worker = CreateWorker <WorkDoneProgress>(token, router, serializer, onError, onComplete, disposable); worker.OnNext(begin); return(new ProgressObserver <WorkDoneProgressReport>(token, worker, CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))); }
public PartialItemsRequestProgressObservable( ISerializer serializer, ProgressToken token, IObservable <TResult> requestResult, Func <IEnumerable <TItem>, TResult> factory, CancellationToken cancellationToken, Action onCompleteAction ) { _serializer = serializer; _dataSubject = new ReplaySubject <IEnumerable <TItem> >(int.MaxValue, Scheduler.Immediate); _disposable = new CompositeDisposable() { _dataSubject }; _task = Observable.Create <TResult>( observer => new CompositeDisposable() { _dataSubject .Aggregate( new List <TItem>(), (acc, data) => { acc.AddRange(data); return(acc); } ) .Select(factory) .ForkJoin( requestResult .Do( result => _dataSubject.OnNext(result ?? Enumerable.Empty <TItem>()), _dataSubject.OnError, _dataSubject.OnCompleted ), (items, result) => items?.Count() > result?.Count() ? items : result ) .Subscribe(observer), Disposable.Create(onCompleteAction) } ) .ToTask(cancellationToken); ProgressToken = token; }
public async Task Should_Send_Progress_From_Client_To_Server() { var token = new ProgressToken(Guid.NewGuid().ToString()); using var observer = Server.ProgressManager.For <Data>(token, CancellationToken); var workDoneObservable = Client.ProgressManager.Monitor(token, x => x.ToObject <Data>(Client.Services.GetRequiredService <ISerializer>().JsonSerializer)); var observable = workDoneObservable.Replay(); using var _ = observable.Connect(); observer.OnNext( new Data { Value = "1" } ); observer.OnNext( new Data { Value = "3" } ); observer.OnNext( new Data { Value = "2" } ); observer.OnNext( new Data { Value = "4" } ); observer.OnNext( new Data { Value = "5" } ); await Task.Delay(1000); workDoneObservable.Dispose(); var data = await observable.Select(z => z.Value).ToArray().ToTask(CancellationToken); data.Should().ContainInOrder(new [] { "1", "3", "2", "4", "5" }); }
public static ProgressObserver <WorkDoneProgressReport> CreateWorkDoneProgress( IResponseRouter router, ISerializer serializer, WorkDoneProgressBegin begin, Func <Exception, WorkDoneProgressEnd> onError, Func <WorkDoneProgressEnd> onComplete, CancellationToken cancellationToken) { var token = new ProgressToken(Guid.NewGuid().ToString()); var earlyEvents = new AsyncSubject <List <WorkDoneProgress> >(); var observer = new Subject <WorkDoneProgress>(); var disposable = new CompositeDisposable { observer, earlyEvents }; var worker = CreateWorker <WorkDoneProgress>(token, router, serializer, onError, onComplete, disposable); disposable.Add( observer .Scan(new List <WorkDoneProgress>() { begin }, (acc, v) => { acc.Add(v); return(acc); }) .Subscribe(earlyEvents.OnNext) ); disposable.Add( Observable.FromAsync(ct => router.CreateProgress(token, ct)) .Subscribe(_ => { }, e => { }, () => { earlyEvents.OnCompleted(); }) ); disposable.Add( earlyEvents .SelectMany(z => z) .Concat(observer) .Subscribe(worker) ); return(new ProgressObserver <WorkDoneProgressReport>(token, observer, CancellationTokenSource.CreateLinkedTokenSource(cancellationToken))); }
public PartialItemRequestProgressObservable( ISerializer serializer, ProgressToken token, IObservable <TResult> requestResult, Func <TItem, TResult, TResult> factory, Func <TResult, TItem> reverseFactory, CancellationToken cancellationToken, Action onCompleteAction ) { _serializer = serializer; _dataSubject = new ReplaySubject <TItem>(1, Scheduler.Immediate); _disposable = new CompositeDisposable { _dataSubject }; _task = Observable.Create <TResult>( observer => new CompositeDisposable { _dataSubject .ForkJoin( requestResult .Do( _ => { if (_receivedPartialData) { return; } _dataSubject.OnNext(reverseFactory(_)); }, _dataSubject.OnError, _dataSubject.OnCompleted ), factory ) .Subscribe(observer), Disposable.Create(onCompleteAction) } ) .ToTask(cancellationToken); ProgressToken = token; }
public void StartMachineTest() { Mock <IProgress> progressMock = new Mock <IProgress>(); int i = 0; progressMock.SetupGet(x => x.Completed).Returns(i).Callback(() => i = 1); //return 0 once, then 1 _mockedComMachine.Setup(x => x.LaunchVMProcess(It.IsAny <Session>(), It.IsAny <string>(), It.IsAny <string>())).Returns(progressMock.Object); ComMachineProxy machineProxy = new ComMachineProxy(_mockedComMachine.Object); ProgressToken t = machineProxy.Start(); Assert.IsInstanceOfType(t, typeof(ComMachineProxy.IProgressProgressToken)); t.Wait(); progressMock.Verify(x => x.WaitForCompletion(It.IsAny <int>())); }
public WorkDoneObserver( ProgressToken progressToken, IResponseRouter router, ISerializer serializer, WorkDoneProgressBegin begin, Func <Exception, WorkDoneProgressEnd> onError, Func <WorkDoneProgressEnd> onComplete, CancellationToken cancellationToken) { _progressToken = progressToken; _router = router; _serializer = serializer; _onError = onError; _onComplete = onComplete; _disposable = new CompositeDisposable { Disposable.Create(OnCompleted) }; cancellationToken.Register(Dispose); OnNext(begin); }
private static void Lookup(ProgressToken token, DiscMetadata.RawMetadata raw, DiscMetadata.DerivedMetadata derived) { var provider = new IsanMetadataProvider(token); provider.Populate(raw.V_ISAN); var isan = raw.ISAN; if (isan != null && !string.IsNullOrWhiteSpace(isan.Title)) { // TODO: Get language from isan.org // Don't insert twice if (!derived.SearchQueries.Any(query => query.Title == isan.Title && query.Year == isan.Year)) { derived.SearchQueries.Insert(0, new SearchQuery { Title = isan.Title, Year = isan.Year }); } } }
public async Task<List<WriteableBitmap>> Animate(int renderWidth, int renderHeight, TimeSpan length, ProgressToken token, ParameterBinding start, ParameterBinding end) { const int parallelism = 1; // TODO change _lastRot variables so animations can be rendered in parallel var totalFrames = (int)length.TotalSeconds*AnimationFps; var frames = new List<WriteableBitmap>(); for (var frame = 0; frame < totalFrames; frame += parallelism) { var frameBindings = Enumerable.Range(frame, parallelism).Select(i => start.Interpolate(end, i, totalFrames)); var renderTasks = frameBindings.Select(b => RenderAsync(renderWidth, renderHeight, b, null)); var rendered = await Task.WhenAll(renderTasks); frames.AddRange(rendered); if (token != null) { token.Value = (int)((float)frame / totalFrames * 100); } } return frames; }