Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 767cc86

Browse files
add ExecutionInfo for unExecution
1 parent 94e1cb3 commit 767cc86

File tree

4 files changed

+253
-175
lines changed

4 files changed

+253
-175
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace SimpleStateMachineNodeEditor.Helpers.Commands
6+
{
7+
public enum ExecutionDemarcation
8+
{
9+
Begin,
10+
Result,
11+
End
12+
}
13+
14+
public struct ExecutionInfo<TResult>
15+
{
16+
private readonly ExecutionDemarcation _demarcation;
17+
private readonly TResult _result;
18+
19+
private ExecutionInfo(ExecutionDemarcation demarcation, TResult result)
20+
{
21+
_demarcation = demarcation;
22+
_result = result;
23+
}
24+
25+
public ExecutionDemarcation Demarcation => _demarcation;
26+
27+
public TResult Result => _result;
28+
29+
public static ExecutionInfo<TResult> CreateBegin() =>
30+
new ExecutionInfo<TResult>(ExecutionDemarcation.Begin, default!);
31+
32+
public static ExecutionInfo<TResult> CreateResult(TResult result) =>
33+
new ExecutionInfo<TResult>(ExecutionDemarcation.Result, result);
34+
35+
public static ExecutionInfo<TResult> CreateEnd() =>
36+
new ExecutionInfo<TResult>(ExecutionDemarcation.End, default!);
37+
}
38+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// Copyright (c) 2020 .NET Foundation and Contributors. All rights reserved.
2+
// Licensed to the .NET Foundation under one or more agreements.
3+
// The .NET Foundation licenses this file to you under the MIT license.
4+
// See the LICENSE file in the project root for full license information.
5+
6+
namespace System.Reactive.Linq
7+
{
8+
/// <summary>
9+
/// Provides commonly required, statically-allocated, pre-canned observables.
10+
/// </summary>
11+
/// <typeparam name="T">
12+
/// The observable type.
13+
/// </typeparam>
14+
internal static class Observable<T>
15+
{
16+
/// <summary>
17+
/// An empty observable of type <typeparamref name="T"/>.
18+
/// </summary>
19+
public static readonly IObservable<T> Empty = Observable.Empty<T>();
20+
21+
/// <summary>
22+
/// An observable of type <typeparamref name="T"/> that never ticks a value.
23+
/// </summary>
24+
public static readonly IObservable<T> Never = Observable.Never<T>();
25+
26+
/// <summary>
27+
/// An observable of type <typeparamref name="T"/> that ticks a single, default value.
28+
/// </summary>
29+
public static readonly IObservable<T> Default = Observable.Return(default(T) !);
30+
}
31+
}

‎SimpleStateMachineNodeEditor/Helpers/Commands/ReactiveCommandWithUndoRedo.cs

Lines changed: 149 additions & 175 deletions
Original file line numberDiff line numberDiff line change
@@ -8,179 +8,153 @@
88

99
namespace SimpleStateMachineNodeEditor.Helpers.Commands
1010
{
11-
//public class ReactiveCommandWithUndoRedo<TParam, TResult> : ReactiveCommandBase<TParam, TResult>
12-
//{
13-
// private readonly Func<TParam, IObservable<TResult>> _execute;
14-
// private readonly IScheduler _outputScheduler;
15-
// private readonly Subject<ExecutionInfo> _executionInfo;
16-
// private readonly ISubject<ExecutionInfo, ExecutionInfo> _synchronizedExecutionInfo;
17-
// private readonly IObservable<bool> _isExecuting;
18-
// private readonly IObservable<bool> _canExecute;
19-
// private readonly IObservable<TResult> _results;
20-
// private readonly ScheduledSubject<Exception> _exceptions;
21-
// private readonly IDisposable _canExecuteSubscription;
22-
23-
// /// <summary>
24-
// /// Initializes a new instance of the <see cref="ReactiveCommand{TParam, TResult}"/> class.
25-
// /// </summary>
26-
// /// <param name="execute">The Func to perform when the command is executed.</param>
27-
// /// <param name="canExecute">A observable which has a value if the command can execute.</param>
28-
// /// <param name="outputScheduler">The scheduler where to send output after the main execution.</param>
29-
// /// <exception cref="ArgumentNullException">Thrown if any dependent parameters are null.</exception>
30-
// protected internal ReactiveCommand(
31-
// Func<TParam, IObservable<TResult>> execute,
32-
// IObservable<bool>? canExecute,
33-
// IScheduler? outputScheduler)
34-
// {
35-
// if (execute == null)
36-
// {
37-
// throw new ArgumentNullException(nameof(execute));
38-
// }
39-
40-
// if (canExecute == null)
41-
// {
42-
// throw new ArgumentNullException(nameof(canExecute));
43-
// }
44-
45-
// if (outputScheduler == null)
46-
// {
47-
// throw new ArgumentNullException(nameof(outputScheduler));
48-
// }
49-
50-
// _execute = execute;
51-
// _outputScheduler = outputScheduler;
52-
// _executionInfo = new Subject<ExecutionInfo>();
53-
// _synchronizedExecutionInfo = Subject.Synchronize(_executionInfo, outputScheduler);
54-
// _isExecuting = _synchronizedExecutionInfo
55-
// .Scan(
56-
// 0,
57-
// (acc, next) =>
58-
// {
59-
// if (next.Demarcation == ExecutionDemarcation.Begin)
60-
// {
61-
// return acc + 1;
62-
// }
63-
64-
// if (next.Demarcation == ExecutionDemarcation.End)
65-
// {
66-
// return acc - 1;
67-
// }
68-
69-
// return acc;
70-
// })
71-
// .Select(inFlightCount => inFlightCount > 0)
72-
// .StartWith(false)
73-
// .DistinctUntilChanged()
74-
// .Replay(1)
75-
// .RefCount();
76-
// _canExecute = canExecute
77-
// .Catch<bool, Exception>(ex =>
78-
// {
79-
// _exceptions.OnNext(ex);
80-
// return Observables.False;
81-
// })
82-
// .StartWith(false)
83-
// .CombineLatest(_isExecuting, (canEx, isEx) => canEx && !isEx)
84-
// .DistinctUntilChanged()
85-
// .Replay(1)
86-
// .RefCount();
87-
// _results = _synchronizedExecutionInfo
88-
// .Where(x => x.Demarcation == ExecutionDemarcation.Result)
89-
// .Select(x => x.Result);
90-
91-
// _exceptions = new ScheduledSubject<Exception>(outputScheduler, RxApp.DefaultExceptionHandler);
92-
93-
// _canExecuteSubscription = _canExecute.Subscribe(OnCanExecuteChanged);
94-
// }
95-
96-
// private enum ExecutionDemarcation
97-
// {
98-
// Begin,
99-
// Result,
100-
// End
101-
// }
102-
103-
// /// <inheritdoc/>
104-
// public override IObservable<bool> CanExecute => _canExecute;
105-
106-
// /// <inheritdoc/>
107-
// public override IObservable<bool> IsExecuting => _isExecuting;
108-
109-
// /// <inheritdoc/>
110-
// public override IObservable<Exception> ThrownExceptions => _exceptions.AsObservable();
111-
112-
// /// <inheritdoc/>
113-
// public override IDisposable Subscribe(IObserver<TResult> observer)
114-
// {
115-
// return _results.Subscribe(observer);
116-
// }
117-
118-
// /// <inheritdoc/>
119-
// public override IObservable<TResult> Execute(TParam parameter = default(TParam))
120-
// {
121-
// try
122-
// {
123-
// return Observable
124-
// .Defer(
125-
// () =>
126-
// {
127-
// _synchronizedExecutionInfo.OnNext(ExecutionInfo.CreateBegin());
128-
// return Observable<TResult>.Empty;
129-
// })
130-
// .Concat(_execute(parameter))
131-
// .Do(result => _synchronizedExecutionInfo.OnNext(ExecutionInfo.CreateResult(result)))
132-
// .Catch<TResult, Exception>(
133-
// ex =>
134-
// {
135-
// _exceptions.OnNext(ex);
136-
// return Observable.Throw<TResult>(ex);
137-
// })
138-
// .Finally(() => _synchronizedExecutionInfo.OnNext(ExecutionInfo.CreateEnd()))
139-
// .PublishLast()
140-
// .RefCount()
141-
// .ObserveOn(_outputScheduler);
142-
// }
143-
// catch (Exception ex)
144-
// {
145-
// _exceptions.OnNext(ex);
146-
// return Observable.Throw<TResult>(ex);
147-
// }
148-
// }
149-
150-
// /// <inheritdoc/>
151-
// protected override void Dispose(bool disposing)
152-
// {
153-
// if (disposing)
154-
// {
155-
// _executionInfo?.Dispose();
156-
// _exceptions?.Dispose();
157-
// _canExecuteSubscription?.Dispose();
158-
// }
159-
// }
160-
161-
// private struct ExecutionInfo
162-
// {
163-
// private readonly ExecutionDemarcation _demarcation;
164-
// private readonly TResult _result;
165-
166-
// private ExecutionInfo(ExecutionDemarcation demarcation, TResult result)
167-
// {
168-
// _demarcation = demarcation;
169-
// _result = result;
170-
// }
171-
172-
// public ExecutionDemarcation Demarcation => _demarcation;
173-
174-
// public TResult Result => _result;
175-
176-
// public static ExecutionInfo CreateBegin() =>
177-
// new ExecutionInfo(ExecutionDemarcation.Begin, default!);
178-
179-
// public static ExecutionInfo CreateResult(TResult result) =>
180-
// new ExecutionInfo(ExecutionDemarcation.Result, result);
181-
182-
// public static ExecutionInfo CreateEnd() =>
183-
// new ExecutionInfo(ExecutionDemarcation.End, default!);
184-
// }
185-
//}
11+
12+
public class ReactiveCommandWithUndoRedo<TParam, TResult> : ReactiveCommandWithUndoRedoBase<TParam, TResult>
13+
{
14+
private readonly ReactiveCommand<TParam, TResult> _command;
15+
private readonly IDisposable _canUnExecuteSubscription;
16+
private readonly ScheduledSubject<Exception> _exceptions;
17+
18+
private readonly Subject<ExecutionInfo<TResult>> _unExecutionInfo;
19+
private readonly ISubject<ExecutionInfo<TResult>, ExecutionInfo<TResult>> _synchronizedUnExecutionInfo;
20+
private readonly IScheduler _outputScheduler;
21+
22+
private readonly Func<TParam, IObservable<TResult>, IObservable<TResult>> _unExecute;
23+
private readonly IObservable<bool> _canUnExecute;
24+
private readonly IObservable<bool> _isUnExecuting;
25+
private TParam _parameter;
26+
private IObservable<TResult> _result;
27+
28+
protected internal ReactiveCommandWithUndoRedo(
29+
Func<TParam, IObservable<TResult>> execute,
30+
Func<TParam, IObservable<TResult>, IObservable<TResult>> unExecute,
31+
IObservable<bool>? canExecute,
32+
IObservable<bool>? canUnExecute,
33+
IScheduler? outputScheduler)
34+
{
35+
_outputScheduler = outputScheduler;
36+
if (unExecute == null)
37+
{
38+
throw new ArgumentNullException(nameof(unExecute));
39+
}
40+
41+
if (canUnExecute == null)
42+
{
43+
throw new ArgumentNullException(nameof(canUnExecute));
44+
}
45+
46+
//_command = ReactiveCommand.CreateFromObservable<TParam, IList<TResult>>(execute, canExecute, outputScheduler);
47+
48+
_unExecute = unExecute;
49+
50+
_unExecutionInfo = new Subject<ExecutionInfo<TResult>>();
51+
_synchronizedUnExecutionInfo = Subject.Synchronize(_unExecutionInfo, outputScheduler);
52+
_isUnExecuting = _synchronizedUnExecutionInfo
53+
.Scan(
54+
0,
55+
(acc, next) =>
56+
{
57+
if (next.Demarcation == ExecutionDemarcation.Begin)
58+
{
59+
return acc + 1;
60+
}
61+
62+
if (next.Demarcation == ExecutionDemarcation.End)
63+
{
64+
return acc - 1;
65+
}
66+
67+
return acc;
68+
})
69+
.Select(inFlightCount => inFlightCount > 0)
70+
.StartWith(false)
71+
.DistinctUntilChanged()
72+
.Replay(1)
73+
.RefCount();
74+
75+
_canUnExecute = canUnExecute
76+
.Catch<bool, Exception>(ex =>
77+
{
78+
_exceptions.OnNext(ex);
79+
return Observables.False;
80+
})
81+
.StartWith(false)
82+
.CombineLatest(_isUnExecuting, (canEx, isEx) => canEx && !isEx)
83+
.DistinctUntilChanged()
84+
.Replay(1)
85+
.RefCount();
86+
87+
_command
88+
.ThrownExceptions
89+
.Subscribe();
90+
_exceptions = new ScheduledSubject<Exception>(outputScheduler, RxApp.DefaultExceptionHandler);
91+
92+
_canUnExecuteSubscription = _canUnExecute.Subscribe(OnCanUnExecuteChanged);
93+
}
94+
95+
96+
public override IObservable<bool> CanExecute => _command.CanExecute;
97+
98+
public override IObservable<bool> IsExecuting => _command.IsExecuting;
99+
public override IObservable<Exception> ThrownExceptions => _command.ThrownExceptions;
100+
101+
public override IObservable<bool> CanUnExecute => _command.CanExecute.Where(x => !x);
102+
103+
public override IObservable<bool> IsUnExecuting => _isUnExecuting;
104+
105+
public override IObservable<TResult> Execute(TParam parameter = default(TParam))
106+
{
107+
_parameter = parameter;
108+
return _command.Execute(parameter);
109+
}
110+
111+
protected override void Dispose(bool disposing)
112+
{
113+
if (disposing)
114+
{
115+
_command.Dispose();
116+
_unExecutionInfo?.Dispose();
117+
_exceptions?.Dispose();
118+
_canUnExecuteSubscription?.Dispose();
119+
}
120+
}
121+
/// <inheritdoc/>
122+
public IObservable<TResult> UnExecute()
123+
{
124+
125+
try
126+
{
127+
return Observable
128+
.Defer(
129+
() =>
130+
{
131+
_synchronizedUnExecutionInfo.OnNext(ExecutionInfo<TResult>.CreateBegin());
132+
return Observable<TResult>.Empty;
133+
})
134+
.Concat(_unExecute(_parameter, _result))
135+
.Do(result => _synchronizedUnExecutionInfo.OnNext(ExecutionInfo<TResult>.CreateResult(result)))
136+
.Catch<TResult, Exception>(
137+
ex =>
138+
{
139+
_exceptions.OnNext(ex);
140+
return Observable.Throw<TResult>(ex);
141+
})
142+
.Finally(() => _synchronizedUnExecutionInfo.OnNext(ExecutionInfo<TResult>.CreateEnd()))
143+
.PublishLast()
144+
.RefCount()
145+
.ObserveOn(_outputScheduler);
146+
}
147+
catch (Exception ex)
148+
{
149+
_exceptions.OnNext(ex);
150+
return Observable.Throw<TResult>(ex);
151+
}
152+
153+
}
154+
public override IDisposable Subscribe(IObserver<TResult> observer)
155+
{
156+
return _command.Subscribe(observer);
157+
}
158+
159+
}
186160
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /