WIP CommandScheduler UI
This commit is contained in:
@@ -2,6 +2,7 @@ namespace FileTime.Core.Command;
|
||||
|
||||
public enum ExecutionState
|
||||
{
|
||||
Initializing,
|
||||
Waiting,
|
||||
Running,
|
||||
Finished
|
||||
|
||||
@@ -4,6 +4,10 @@ namespace FileTime.Core.Command;
|
||||
|
||||
public interface ICommand
|
||||
{
|
||||
IObservable<string> DisplayLabel { get; }
|
||||
IObservable<int> TotalProgress { get; }
|
||||
IObservable<int> CurrentProgress { get; }
|
||||
|
||||
Task<CanCommandRun> CanRun(PointInTime currentTime);
|
||||
Task<PointInTime> SimulateCommand(PointInTime currentTime);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using DynamicData;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.Core.Extensions;
|
||||
|
||||
public static class BindedCollectionExtensions
|
||||
{
|
||||
public static BindedCollection<T> ToBindedCollection<T>(this IObservable<IChangeSet<T>> source)
|
||||
{
|
||||
return new BindedCollection<T>(source);
|
||||
}
|
||||
|
||||
public static BindedCollection<T> ToBindedCollection<T>(this IObservable<IObservable<IChangeSet<T>>?> source)
|
||||
{
|
||||
return new BindedCollection<T>(source);
|
||||
}
|
||||
|
||||
public static BindedCollection<T, TKey> ToBindedCollection<T, TKey>(this IObservable<IChangeSet<T, TKey>> source) where TKey : notnull
|
||||
{
|
||||
return new BindedCollection<T, TKey>(source);
|
||||
}
|
||||
|
||||
public static BindedCollection<T, TKey> ToBindedCollection<T, TKey>(this IObservable<IObservable<IChangeSet<T, TKey>>?> source) where TKey : notnull
|
||||
{
|
||||
return new BindedCollection<T, TKey>(source);
|
||||
}
|
||||
}
|
||||
@@ -53,7 +53,7 @@ public static class DynamicDataExtensions
|
||||
this IObservable<IChangeSet<AbsolutePath, string>> stream)
|
||||
=> await GetItemsAsync(stream.ToCollection());
|
||||
|
||||
private static Task<IEnumerable<AbsolutePath>?> GetItemsAsync(
|
||||
public static Task<IEnumerable<AbsolutePath>?> GetItemsAsync(
|
||||
this IObservable<IReadOnlyCollection<AbsolutePath>> stream)
|
||||
{
|
||||
var taskCompletionSource = new TaskCompletionSource<IEnumerable<AbsolutePath>?>();
|
||||
|
||||
106
src/Core/FileTime.Core.Abstraction/Models/BindedCollection.cs
Normal file
106
src/Core/FileTime.Core.Abstraction/Models/BindedCollection.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using DynamicData;
|
||||
using PropertyChanged.SourceGenerator;
|
||||
|
||||
namespace FileTime.Core.Models;
|
||||
|
||||
public partial class BindedCollection<T> : IDisposable, INotifyPropertyChanged
|
||||
{
|
||||
private readonly IDisposable? _disposable;
|
||||
private IDisposable? _innerDisposable;
|
||||
|
||||
[Notify] private ReadOnlyObservableCollection<T>? _collection;
|
||||
|
||||
public BindedCollection()
|
||||
{
|
||||
}
|
||||
|
||||
public BindedCollection(IObservable<IChangeSet<T>> dynamicList)
|
||||
{
|
||||
_disposable = dynamicList
|
||||
.Bind(out var collection)
|
||||
.DisposeMany()
|
||||
.Subscribe();
|
||||
|
||||
_collection = collection;
|
||||
}
|
||||
|
||||
public BindedCollection(IObservable<IObservable<IChangeSet<T>>?> dynamicListSource)
|
||||
{
|
||||
_disposable = dynamicListSource.Subscribe(dynamicList =>
|
||||
{
|
||||
_innerDisposable?.Dispose();
|
||||
if (dynamicList is not null)
|
||||
{
|
||||
_innerDisposable = dynamicList
|
||||
.Bind(out var collection)
|
||||
.DisposeMany()
|
||||
.Subscribe();
|
||||
|
||||
Collection = collection;
|
||||
}
|
||||
else
|
||||
{
|
||||
Collection = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_disposable?.Dispose();
|
||||
_innerDisposable?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
|
||||
public partial class BindedCollection<T, TKey> : IDisposable, INotifyPropertyChanged where TKey : notnull
|
||||
{
|
||||
private readonly IDisposable? _disposable;
|
||||
private IDisposable? _innerDisposable;
|
||||
|
||||
[Notify] private ReadOnlyObservableCollection<T>? _collection;
|
||||
|
||||
public BindedCollection()
|
||||
{
|
||||
}
|
||||
|
||||
public BindedCollection(IObservable<IChangeSet<T, TKey>> dynamicList)
|
||||
{
|
||||
_disposable = dynamicList
|
||||
.Bind(out var collection)
|
||||
.DisposeMany()
|
||||
.Subscribe();
|
||||
|
||||
_collection = collection;
|
||||
}
|
||||
|
||||
public BindedCollection(IObservable<IObservable<IChangeSet<T, TKey>>?> dynamicListSource)
|
||||
{
|
||||
_disposable = dynamicListSource.Subscribe(dynamicList =>
|
||||
{
|
||||
_innerDisposable?.Dispose();
|
||||
if (dynamicList is not null)
|
||||
{
|
||||
_innerDisposable = dynamicList
|
||||
.Bind(out var collection)
|
||||
.DisposeMany()
|
||||
.Subscribe();
|
||||
|
||||
Collection = collection;
|
||||
}
|
||||
else
|
||||
{
|
||||
Collection = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_disposable?.Dispose();
|
||||
_innerDisposable?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
@@ -4,18 +4,50 @@ namespace FileTime.Core.Timeline;
|
||||
|
||||
public class CommandTimeState
|
||||
{
|
||||
private object _executionStateLock = new object();
|
||||
private ExecutionState _executionState;
|
||||
public ICommand Command { get; }
|
||||
public CanCommandRun CanRun { get; private set; } = CanCommandRun.False;
|
||||
public bool ForceRun { get; set; }
|
||||
public ExecutionState ExecutionState { get; set; }
|
||||
|
||||
public ExecutionState ExecutionState
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_executionStateLock)
|
||||
{
|
||||
return _executionState;
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
lock (_executionStateLock)
|
||||
{
|
||||
_executionState = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public CommandTimeState(ICommand command)
|
||||
{
|
||||
Command = command;
|
||||
SetToWait();
|
||||
}
|
||||
|
||||
public async Task UpdateStateAsync(PointInTime? startPoint)
|
||||
{
|
||||
CanRun = startPoint == null ? CanCommandRun.False : await Command.CanRun(startPoint);
|
||||
}
|
||||
|
||||
private async void SetToWait()
|
||||
{
|
||||
// This command won't be shown in the scheduler until this timeout is over
|
||||
// Short living commands while not "blink on" the list
|
||||
await Task.Delay(100);
|
||||
lock (_executionStateLock)
|
||||
{
|
||||
if (_executionState == ExecutionState.Initializing)
|
||||
_executionState = ExecutionState.Waiting;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using DynamicData;
|
||||
using FileTime.Core.Command;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
@@ -7,5 +8,8 @@ public interface ICommandScheduler
|
||||
{
|
||||
Task AddCommand(ICommand command, int? batchId = null, bool toNewBatch = false);
|
||||
IObservable<FullName> ContainerToRefresh { get; }
|
||||
IObservable<IChangeSet<ParallelCommands>> CommandsToRun { get; }
|
||||
bool IsRunningEnabled { get; }
|
||||
void RefreshContainer(FullName container);
|
||||
Task SetRunningEnabledAsync(bool value);
|
||||
}
|
||||
@@ -1,15 +1,32 @@
|
||||
using DynamicData;
|
||||
using FileTime.Core.Command;
|
||||
using FileTime.Core.Extensions;
|
||||
using FileTime.Core.Models;
|
||||
|
||||
namespace FileTime.Core.Timeline;
|
||||
|
||||
public class ParallelCommands
|
||||
public class ParallelCommands : IDisposable
|
||||
{
|
||||
private static ushort _idCounter;
|
||||
private List<CommandTimeState> _commands;
|
||||
private readonly SourceList<CommandTimeState> _commands;
|
||||
private PointInTime? _startTime;
|
||||
|
||||
public ushort Id { get; }
|
||||
public IReadOnlyList<CommandTimeState> Commands { get; }
|
||||
|
||||
public IObservable<IChangeSet<CommandTimeState>> Commands { get; }
|
||||
|
||||
public BindedCollection<CommandTimeState> CommandsCollection { get; }
|
||||
|
||||
public PointInTime? Result { get; private set; }
|
||||
|
||||
public PointInTime? StartTime => _startTime;
|
||||
|
||||
public async Task<PointInTime?> SetStartTimeAsync(PointInTime? startTime)
|
||||
{
|
||||
_startTime = startTime;
|
||||
return await RefreshResult();
|
||||
}
|
||||
|
||||
public ParallelCommands(PointInTime? result)
|
||||
: this(new List<CommandTimeState>(), result)
|
||||
{
|
||||
@@ -19,8 +36,10 @@ public class ParallelCommands
|
||||
{
|
||||
Id = _idCounter++;
|
||||
|
||||
_commands = commands;
|
||||
Commands = _commands.AsReadOnly();
|
||||
_commands = new SourceList<CommandTimeState>();
|
||||
_commands.Edit((innerList) => innerList.AddRange(commands));
|
||||
Commands = _commands.Connect();
|
||||
CommandsCollection = Commands.ToBindedCollection();
|
||||
|
||||
Result = result;
|
||||
}
|
||||
@@ -63,10 +82,17 @@ public class ParallelCommands
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<PointInTime?> RefreshResult(PointInTime? startPoint)
|
||||
public async Task RemoveCommand(ICommand command)
|
||||
{
|
||||
var result = startPoint;
|
||||
foreach (var commandTimeState in _commands)
|
||||
var commandTimeState = _commands.Items.First(c => c.Command == command);
|
||||
_commands.Remove(commandTimeState);
|
||||
await RefreshResult();
|
||||
}
|
||||
|
||||
public async Task<PointInTime?> RefreshResult()
|
||||
{
|
||||
var result = StartTime;
|
||||
foreach (var commandTimeState in _commands.Items)
|
||||
{
|
||||
await commandTimeState.UpdateStateAsync(result);
|
||||
if (result != null)
|
||||
@@ -87,7 +113,8 @@ public class ParallelCommands
|
||||
return Result;
|
||||
}
|
||||
|
||||
public void RemoveAt(int number) => _commands.RemoveAt(number);
|
||||
|
||||
internal void Remove(CommandTimeState command) => _commands.Remove(command);
|
||||
public void Dispose()
|
||||
{
|
||||
CommandsCollection.Dispose();
|
||||
}
|
||||
}
|
||||
36
src/Core/FileTime.Core.Command/CommandBase.cs
Normal file
36
src/Core/FileTime.Core.Command/CommandBase.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System.Reactive.Linq;
|
||||
using System.Reactive.Subjects;
|
||||
using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command;
|
||||
|
||||
public abstract class CommandBase : ICommand
|
||||
{
|
||||
private readonly BehaviorSubject<string> _displayLabel;
|
||||
private readonly BehaviorSubject<int> _totalProgress;
|
||||
private readonly BehaviorSubject<int> _currentProgress;
|
||||
|
||||
public IObservable<string> DisplayLabel { get; }
|
||||
public IObservable<int> TotalProgress { get; }
|
||||
public IObservable<int> CurrentProgress { get; }
|
||||
|
||||
protected CommandBase(string displayLabel = "", int totalProgress = 0, int currentProgress = 0)
|
||||
{
|
||||
_displayLabel = new(displayLabel);
|
||||
_totalProgress = new(totalProgress);
|
||||
_currentProgress = new(currentProgress);
|
||||
|
||||
DisplayLabel = _displayLabel.AsObservable();
|
||||
TotalProgress = _totalProgress.AsObservable();
|
||||
CurrentProgress = _currentProgress.AsObservable();
|
||||
}
|
||||
|
||||
public abstract Task<CanCommandRun> CanRun(PointInTime currentTime);
|
||||
public abstract Task<PointInTime> SimulateCommand(PointInTime currentTime);
|
||||
|
||||
protected void SetDisplayLabel(string displayLabel) => _displayLabel.OnNext(displayLabel);
|
||||
|
||||
protected void SetTotalProgress(int totalProgress) => _totalProgress.OnNext(totalProgress);
|
||||
|
||||
protected void SetCurrentProgress(int currentProgress) => _currentProgress.OnNext(currentProgress);
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command.Copy;
|
||||
|
||||
public class CopyCommand : ITransportationCommand
|
||||
public class CopyCommand : CommandBase, ITransportationCommand
|
||||
{
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly ICommandSchedulerNotifier _commandSchedulerNotifier;
|
||||
@@ -22,18 +22,19 @@ public class CopyCommand : ITransportationCommand
|
||||
public CopyCommand(
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
ICommandSchedulerNotifier commandSchedulerNotifier)
|
||||
: base("Copy")
|
||||
{
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
_commandSchedulerNotifier = commandSchedulerNotifier;
|
||||
}
|
||||
|
||||
public Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
public override Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
{
|
||||
//TODO:
|
||||
return Task.FromResult(CanCommandRun.True);
|
||||
}
|
||||
|
||||
public async Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
public override async Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
{
|
||||
if (Sources == null) throw new ArgumentException(nameof(Sources) + " can not be null");
|
||||
if (Target == null) throw new ArgumentException(nameof(Target) + " can not be null");
|
||||
|
||||
@@ -7,7 +7,7 @@ using InitableService;
|
||||
|
||||
namespace FileTime.Core.Command.Create;
|
||||
|
||||
public abstract class CreateItemBase : IExecutableCommand, IInitable<FullName, string>
|
||||
public abstract class CreateItemBase : CommandBase, IExecutableCommand, IInitable<FullName, string>
|
||||
{
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
@@ -17,12 +17,13 @@ public abstract class CreateItemBase : IExecutableCommand, IInitable<FullName, s
|
||||
protected CreateItemBase(
|
||||
ITimelessContentProvider timelessContentProvider,
|
||||
IContentAccessorFactory contentAccessorFactory)
|
||||
: base("Create")
|
||||
{
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
}
|
||||
|
||||
public async Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
public override async Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
{
|
||||
if (Parent is null)
|
||||
{
|
||||
@@ -49,7 +50,7 @@ public abstract class CreateItemBase : IExecutableCommand, IInitable<FullName, s
|
||||
return existingItem switch
|
||||
{
|
||||
null => CanCommandRun.True,
|
||||
{ Type: AbsolutePathType.Container } => CanCommandRun.Forcable,
|
||||
{Type: AbsolutePathType.Container} => CanCommandRun.Forcable,
|
||||
_ => CanCommandRun.False
|
||||
};
|
||||
}
|
||||
@@ -60,7 +61,7 @@ public abstract class CreateItemBase : IExecutableCommand, IInitable<FullName, s
|
||||
return CanCommandRun.False;
|
||||
}
|
||||
|
||||
public Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
public override Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
{
|
||||
if (Parent is null)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@ using FileTime.Core.Timeline;
|
||||
|
||||
namespace FileTime.Core.Command.Delete;
|
||||
|
||||
public class DeleteCommand : IExecutableCommand
|
||||
public class DeleteCommand : CommandBase, IExecutableCommand
|
||||
{
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
private readonly ITimelessContentProvider _timelessContentProvider;
|
||||
@@ -15,18 +15,19 @@ public class DeleteCommand : IExecutableCommand
|
||||
public DeleteCommand(
|
||||
IContentAccessorFactory contentAccessorFactory,
|
||||
ITimelessContentProvider timelessContentProvider)
|
||||
: base("Delete")
|
||||
{
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
_timelessContentProvider = timelessContentProvider;
|
||||
}
|
||||
|
||||
public Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
public override Task<CanCommandRun> CanRun(PointInTime currentTime)
|
||||
{
|
||||
//TODO
|
||||
return Task.FromResult(CanCommandRun.True);
|
||||
}
|
||||
|
||||
public Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
public override Task<PointInTime> SimulateCommand(PointInTime currentTime)
|
||||
{
|
||||
//TODO
|
||||
return Task.FromResult(currentTime);
|
||||
@@ -38,8 +39,8 @@ public class DeleteCommand : IExecutableCommand
|
||||
|
||||
//Delete
|
||||
await TraverseTree(
|
||||
PointInTime.Present,
|
||||
ItemsToDelete,
|
||||
PointInTime.Present,
|
||||
ItemsToDelete,
|
||||
new Dictionary<string, IItemDeleter>(),
|
||||
new DeleteStrategy()
|
||||
);
|
||||
@@ -69,9 +70,9 @@ public class DeleteCommand : IExecutableCommand
|
||||
if (itemToDelete is IContainer container)
|
||||
{
|
||||
await TraverseTree(
|
||||
currentTime,
|
||||
(await container.Items.GetItemsAsync())?.Select(i => i.Path) ?? Enumerable.Empty<FullName>(),
|
||||
itemDeleters,
|
||||
currentTime,
|
||||
(await container.Items.GetItemsAsync())?.Select(i => i.Path) ?? Enumerable.Empty<FullName>(),
|
||||
itemDeleters,
|
||||
deleteStrategy
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,28 +13,31 @@ public class CommandScheduler : ICommandScheduler
|
||||
private readonly Subject<FullName> _containerToRefresh = new();
|
||||
|
||||
private readonly object _guard = new();
|
||||
private bool _enableRunning = true;
|
||||
private bool _isRunningEnabled = true;
|
||||
private bool _resourceIsInUse;
|
||||
|
||||
public IObservable<FullName> ContainerToRefresh { get; }
|
||||
|
||||
public bool EnableRunning
|
||||
{
|
||||
get
|
||||
{
|
||||
var result = true;
|
||||
RunWithLock(() => result = _enableRunning);
|
||||
return result;
|
||||
}
|
||||
public bool IsRunningEnabled => _isRunningEnabled;
|
||||
|
||||
set { RunWithLock(() => _enableRunning = value); }
|
||||
public async Task SetRunningEnabledAsync(bool value)
|
||||
{
|
||||
_isRunningEnabled = value;
|
||||
if (value)
|
||||
{
|
||||
await RunWithLockAsync(ExecuteCommands);
|
||||
}
|
||||
}
|
||||
|
||||
public IObservable<IChangeSet<ParallelCommands>> CommandsToRun { get; }
|
||||
|
||||
public CommandScheduler(ILocalCommandExecutor localExecutor)
|
||||
{
|
||||
CommandsToRun = _commandsToRun.Connect();
|
||||
|
||||
ContainerToRefresh = _containerToRefresh.AsObservable();
|
||||
|
||||
localExecutor.CommandFinished += LocalExecutorOnCommandFinished;
|
||||
localExecutor.CommandFinished += ExecutorOnCommandFinished;
|
||||
_commandExecutors.Add(localExecutor);
|
||||
}
|
||||
|
||||
@@ -46,6 +49,7 @@ public class CommandScheduler : ICommandScheduler
|
||||
|
||||
if (_commandsToRun.Count == 0)
|
||||
{
|
||||
//TODO: Add event handler to update
|
||||
batchToAdd = new ParallelCommands(PointInTime.CreateEmpty());
|
||||
_commandsToRun.Add(batchToAdd);
|
||||
}
|
||||
@@ -82,13 +86,11 @@ public class CommandScheduler : ICommandScheduler
|
||||
|
||||
private void ExecuteCommands()
|
||||
{
|
||||
if (!_enableRunning) return;
|
||||
if (!_isRunningEnabled) return;
|
||||
|
||||
var parallelCommandsToExecute = _commandsToRun.Items.FirstOrDefault();
|
||||
if (parallelCommandsToExecute is null ||
|
||||
parallelCommandsToExecute.Commands.All(c => c.ExecutionState != ExecutionState.Waiting)) return;
|
||||
var commandsToExecute = _commandsToRun.Items.FirstOrDefault()?.CommandsCollection.Collection;
|
||||
if (commandsToExecute is null || commandsToExecute.All(c => c.ExecutionState != ExecutionState.Initializing && c.ExecutionState != ExecutionState.Waiting)) return;
|
||||
|
||||
var commandsToExecute = parallelCommandsToExecute.Commands;
|
||||
|
||||
foreach (var commandToExecute in commandsToExecute)
|
||||
{
|
||||
@@ -108,15 +110,20 @@ public class CommandScheduler : ICommandScheduler
|
||||
return _commandExecutors[0];
|
||||
}
|
||||
|
||||
private void LocalExecutorOnCommandFinished(object? sender, ICommand command)
|
||||
private async void ExecutorOnCommandFinished(object? sender, ICommand command)
|
||||
{
|
||||
var parallelCommandsToExecute = _commandsToRun.Items.FirstOrDefault();
|
||||
if (parallelCommandsToExecute is null) return;
|
||||
var firstCommandBlock = _commandsToRun
|
||||
.Items
|
||||
.FirstOrDefault();
|
||||
var state = firstCommandBlock
|
||||
?.CommandsCollection
|
||||
.Collection
|
||||
?.FirstOrDefault(c => c.Command == command);
|
||||
|
||||
var state = parallelCommandsToExecute.Commands.FirstOrDefault(c => c.Command == command);
|
||||
if (state is null) return;
|
||||
|
||||
state.ExecutionState = ExecutionState.Finished;
|
||||
if (firstCommandBlock is not null) await firstCommandBlock.RemoveCommand(command);
|
||||
}
|
||||
|
||||
private async Task RefreshCommands()
|
||||
@@ -125,7 +132,7 @@ public class CommandScheduler : ICommandScheduler
|
||||
|
||||
foreach (var batch in _commandsToRun.Items)
|
||||
{
|
||||
currentTime = await batch.RefreshResult(currentTime);
|
||||
currentTime = await batch.SetStartTimeAsync(currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace FileTime.Core.Timeline;
|
||||
public class LocalCommandExecutor : ILocalCommandExecutor
|
||||
{
|
||||
private readonly ICommandRunner _commandRunner;
|
||||
public event EventHandler<ICommand> CommandFinished;
|
||||
public event EventHandler<ICommand>? CommandFinished;
|
||||
|
||||
public LocalCommandExecutor(ICommandRunner commandRunner)
|
||||
{
|
||||
@@ -15,7 +15,7 @@ public class LocalCommandExecutor : ILocalCommandExecutor
|
||||
public void ExecuteCommand(ICommand command)
|
||||
{
|
||||
var context = new CommandRunnerContext(command);
|
||||
var thread = new Thread(new ParameterizedThreadStart(RunCommand));
|
||||
var thread = new Thread(RunCommand);
|
||||
thread.Start(context);
|
||||
}
|
||||
|
||||
@@ -29,6 +29,6 @@ public class LocalCommandExecutor : ILocalCommandExecutor
|
||||
}
|
||||
catch (Exception ex) { }
|
||||
|
||||
CommandFinished.Invoke(this, context.Command);
|
||||
CommandFinished?.Invoke(this, context.Command);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user