Skip to content

Commit 502963d

Browse files
authored
refactor: Remove ReactiveCommand abstract class. (#1836)
1 parent 7803b2e commit 502963d

File tree

13 files changed

+215
-196
lines changed

13 files changed

+215
-196
lines changed

src/ReactiveUI.Fody.Tests/ReactiveUI.Fody.Tests.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
11-
<PackageReference Include="PublicApiGenerator" Version="8.0.0" />
10+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
11+
<PackageReference Include="PublicApiGenerator" Version="8.0.1" />
1212
</ItemGroup>
1313

1414
<ItemGroup>
15-
<PackageReference Include="Shouldly" Version=" 3.0.0" />
15+
<PackageReference Include="Shouldly" Version="3.0.2" />
1616
<PackageReference Include="System.Reactive" Version="4.0.0" />
1717
<PackageReference Include="Microsoft.Reactive.Testing" Version="4.0.0" />
1818
</ItemGroup>

src/ReactiveUI.Tests/API/ApiApprovalTests.ReactiveUI.approved.txt

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -458,13 +458,8 @@ namespace ReactiveUI
458458
public string PropertyName { get; set; }
459459
}
460460
public delegate void PropertyChangingEventHandler(object sender, ReactiveUI.PropertyChangingEventArgs e);
461-
public abstract class ReactiveCommand : ReactiveUI.IHandleObservableErrors, System.IDisposable, System.Windows.Input.ICommand
461+
public class static ReactiveCommand
462462
{
463-
protected ReactiveCommand() { }
464-
public abstract System.IObservable<bool> CanExecute { get; }
465-
public abstract System.IObservable<bool> IsExecuting { get; }
466-
public abstract System.IObservable<System.Exception> ThrownExceptions { get; }
467-
public event System.EventHandler System.Windows.Input.ICommand.CanExecuteChanged;
468463
public static ReactiveUI.ReactiveCommand<System.Reactive.Unit, System.Reactive.Unit> Create(System.Action execute, System.IObservable<bool> canExecute = null, System.Reactive.Concurrency.IScheduler outputScheduler = null) { }
469464
public static ReactiveUI.ReactiveCommand<System.Reactive.Unit, TResult> Create<TResult>(System.Func<TResult> execute, System.IObservable<bool> canExecute = null, System.Reactive.Concurrency.IScheduler outputScheduler = null) { }
470465
public static ReactiveUI.ReactiveCommand<TParam, System.Reactive.Unit> Create<TParam>(System.Action<TParam> execute, System.IObservable<bool> canExecute = null, System.Reactive.Concurrency.IScheduler outputScheduler = null) { }
@@ -480,11 +475,6 @@ namespace ReactiveUI
480475
public static ReactiveUI.ReactiveCommand<TParam, TResult> CreateFromTask<TParam, TResult>(System.Func<TParam, System.Threading.CancellationToken, System.Threading.Tasks.Task<TResult>> execute, System.IObservable<bool> canExecute = null, System.Reactive.Concurrency.IScheduler outputScheduler = null) { }
481476
public static ReactiveUI.ReactiveCommand<TParam, System.Reactive.Unit> CreateFromTask<TParam>(System.Func<TParam, System.Threading.Tasks.Task> execute, System.IObservable<bool> canExecute = null, System.Reactive.Concurrency.IScheduler outputScheduler = null) { }
482477
public static ReactiveUI.ReactiveCommand<TParam, System.Reactive.Unit> CreateFromTask<TParam>(System.Func<TParam, System.Threading.CancellationToken, System.Threading.Tasks.Task> execute, System.IObservable<bool> canExecute = null, System.Reactive.Concurrency.IScheduler outputScheduler = null) { }
483-
public void Dispose() { }
484-
protected abstract void Dispose(bool disposing);
485-
protected abstract bool ICommandCanExecute(object parameter);
486-
protected abstract void ICommandExecute(object parameter);
487-
protected void OnCanExecuteChanged() { }
488478
}
489479
public class ReactiveCommand<TParam, TResult> : ReactiveUI.ReactiveCommandBase<TParam, TResult>
490480
{
@@ -496,12 +486,19 @@ namespace ReactiveUI
496486
public override System.IObservable<TResult> Execute(TParam parameter = null) { }
497487
public override System.IDisposable Subscribe(System.IObserver<TResult> observer) { }
498488
}
499-
public abstract class ReactiveCommandBase<TParam, TResult> : ReactiveUI.ReactiveCommand, System.IObservable<TResult>
489+
public abstract class ReactiveCommandBase<TParam, TResult> : ReactiveUI.IHandleObservableErrors, System.IDisposable, System.IObservable<TResult>, System.Windows.Input.ICommand
500490
{
501491
protected ReactiveCommandBase() { }
492+
public abstract System.IObservable<bool> CanExecute { get; }
493+
public abstract System.IObservable<bool> IsExecuting { get; }
494+
public abstract System.IObservable<System.Exception> ThrownExceptions { get; }
495+
public event System.EventHandler System.Windows.Input.ICommand.CanExecuteChanged;
496+
public void Dispose() { }
497+
protected abstract void Dispose(bool disposing);
502498
public abstract System.IObservable<TResult> Execute(TParam parameter = null);
503-
protected override bool ICommandCanExecute(object parameter) { }
504-
protected override void ICommandExecute(object parameter) { }
499+
protected virtual bool ICommandCanExecute(object parameter) { }
500+
protected virtual void ICommandExecute(object parameter) { }
501+
protected void OnCanExecuteChanged() { }
505502
public abstract System.IDisposable Subscribe(System.IObserver<TResult> observer);
506503
}
507504
public class static ReactiveCommandMixins

src/ReactiveUI.Tests/CommandBindingTests.cs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace ReactiveUI.Tests
1717
{
1818
public class FakeViewModel : ReactiveObject
1919
{
20-
public ReactiveCommand Cmd { get; protected set; }
20+
public ReactiveCommand<Unit, Unit> Cmd { get; protected set; }
2121

2222
public FakeViewModel()
2323
{
@@ -123,9 +123,9 @@ public void EventBinderBindsToImplicitEvent()
123123

124124
public class CommandBindViewModel : ReactiveObject
125125
{
126-
public ReactiveCommand _Command1;
126+
public ReactiveCommand<int, Unit> _Command1;
127127

128-
public ReactiveCommand Command1
128+
public ReactiveCommand<int, Unit> Command1
129129
{
130130
get => _Command1;
131131
set => this.RaiseAndSetIfChanged(ref _Command1, value);
@@ -141,7 +141,7 @@ public ReactiveCommand<Unit, Unit> Command2
141141

142142
public CommandBindViewModel()
143143
{
144-
Command1 = ReactiveCommand.Create(() => { });
144+
Command1 = ReactiveCommand.Create<int, Unit>(_ => Unit.Default);
145145
Command2 = ReactiveCommand.Create(() => { });
146146
}
147147

@@ -163,7 +163,7 @@ public FakeNestedViewModel()
163163
NestedCommand = ReactiveCommand.Create(() => { });
164164
}
165165

166-
public ReactiveCommand NestedCommand { get; protected set; }
166+
public ReactiveCommand<Unit, Unit> NestedCommand { get; protected set; }
167167
}
168168

169169
public class CustomClickButton : Button
@@ -235,7 +235,7 @@ public void CommandBindByNameWireup()
235235
var disp = view.BindCommand(vm, x => x.Command1, x => x.Command1);
236236
Assert.Equal(vm.Command1, view.Command1.Command);
237237

238-
var newCmd = ReactiveCommand.Create(() => { });
238+
var newCmd = ReactiveCommand.Create<int>(_ => { });
239239
vm.Command1 = newCmd;
240240
Assert.Equal(newCmd, view.Command1.Command);
241241

@@ -265,7 +265,7 @@ public void CommandBindSetsInitialEnabledState_True()
265265
var view = new CommandBindView { ViewModel = vm };
266266

267267
var canExecute1 = new BehaviorSubject<bool>(true);
268-
var cmd1 = ReactiveCommand.Create(() => { }, canExecute1);
268+
var cmd1 = ReactiveCommand.Create<int>(_ => { }, canExecute1);
269269
vm.Command1 = cmd1;
270270

271271
var disp = view.BindCommand(vm, x => x.Command1, x => x.Command1);
@@ -280,7 +280,7 @@ public void CommandBindSetsDisablesCommandWhenCanExecuteChanged()
280280
var view = new CommandBindView { ViewModel = vm };
281281

282282
var canExecute1 = new BehaviorSubject<bool>(true);
283-
var cmd1 = ReactiveCommand.Create(() => { }, canExecute1);
283+
var cmd1 = ReactiveCommand.Create<int>(_ => { }, canExecute1);
284284
vm.Command1 = cmd1;
285285

286286
var disp = view.BindCommand(vm, x => x.Command1, x => x.Command1);
@@ -299,7 +299,7 @@ public void CommandBindSetsInitialEnabledState_False()
299299
var view = new CommandBindView { ViewModel = vm };
300300

301301
var canExecute1 = new BehaviorSubject<bool>(false);
302-
var cmd1 = ReactiveCommand.Create(() => { }, canExecute1);
302+
var cmd1 = ReactiveCommand.Create<int>(_ => { }, canExecute1);
303303
vm.Command1 = cmd1;
304304

305305
var disp = view.BindCommand(vm, x => x.Command1, x => x.Command1);
@@ -314,7 +314,7 @@ public void CommandBindRaisesCanExecuteChangedOnBind()
314314
var view = new CommandBindView { ViewModel = vm };
315315

316316
var canExecute1 = new BehaviorSubject<bool>(true);
317-
var cmd1 = ReactiveCommand.Create(() => { }, canExecute1);
317+
var cmd1 = ReactiveCommand.Create<int>(_ => { }, canExecute1);
318318
vm.Command1 = cmd1;
319319

320320
var disp = view.BindCommand(vm, x => x.Command1, x => x.Command1);
@@ -323,7 +323,7 @@ public void CommandBindRaisesCanExecuteChangedOnBind()
323323

324324
// Now change to a disabled cmd
325325
var canExecute2 = new BehaviorSubject<bool>(false);
326-
var cmd2 = ReactiveCommand.Create(() => { }, canExecute2);
326+
var cmd2 = ReactiveCommand.Create<int>(_ => { }, canExecute2);
327327
vm.Command1 = cmd2;
328328

329329
Assert.False(view.Command1.IsEnabled);

src/ReactiveUI.Tests/Platforms/winforms/CommandBindingTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ public void CommandBindToExplicitEventWireup()
215215

216216
public class FakeViewModel : ReactiveObject
217217
{
218-
public ReactiveCommand Cmd { get; protected set; }
218+
public ReactiveCommand<Unit, Unit> Cmd { get; protected set; }
219219

220220
public FakeViewModel()
221221
{

src/ReactiveUI.Tests/ReactiveUI.Tests.csproj

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.8.0" />
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
1212
</ItemGroup>
1313

1414
<ItemGroup>
15-
<PackageReference Include="xunit" Version="2.4.0" />
16-
<PackageReference Include="xunit.runner.console" Version="2.4.0" />
17-
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
18-
<PackageReference Include="Xunit.StaFact" Version="0.2.17" />
19-
<PackageReference Include="Shouldly" Version=" 3.0.0" />
15+
<PackageReference Include="xunit" Version="2.4.1" />
16+
<PackageReference Include="xunit.runner.console" Version="2.4.1" />
17+
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
18+
<PackageReference Include="Xunit.StaFact" Version="0.3.5" />
19+
<PackageReference Include="Shouldly" Version=" 3.0.2" />
2020
<PackageReference Include="Microsoft.Reactive.Testing" Version="4.0.0" />
21-
<PackageReference Include="PublicApiGenerator" Version="8.0.0" />
21+
<PackageReference Include="PublicApiGenerator" Version="8.0.1" />
2222
</ItemGroup>
2323

2424
<ItemGroup>

src/ReactiveUI.Tests/WeakEventManagerTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public class WeakEventManagerTest
1616
public void ButtonDoesNotLeakTest()
1717
{
1818
var button = new Button();
19-
ReactiveCommand command = ReactiveCommand.Create(() => { });
19+
var command = ReactiveCommand.Create(() => { });
2020
button.Command = command;
2121

2222
var buttonRef = new WeakReference(button);

src/ReactiveUI/Bindings/Command/CommandBinderImplementation.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,13 @@ public IReactiveBinding<TView, TViewModel, TProp> BindCommand<TView, TViewModel,
5656

5757
IDisposable bindingDisposable = BindCommandInternal(source, view, controlExpression, Observable.Defer(() => Observable.Return(withParameter())), toEvent, cmd =>
5858
{
59-
var rc = cmd as ReactiveCommand;
59+
var rc = cmd as IReactiveCommand;
6060
if (rc == null)
6161
{
6262
return new RelayCommand(cmd.CanExecute, _ => cmd.Execute(withParameter()));
6363
}
6464

65-
var ret = ReactiveCommand.Create(() => ((ICommand)rc).Execute(null), rc.CanExecute);
66-
return ret;
65+
return ReactiveCommand.Create(() => ((ICommand)rc).Execute(null), rc.CanExecute);
6766
});
6867

6968
return new ReactiveBinding<TView, TViewModel, TProp>(

src/ReactiveUI/EventManagers/WeakEventManager.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,11 +293,11 @@ public bool Matches(object source, TEventHandler handler)
293293
ReferenceEquals(_source.Target, source) &&
294294
_originalHandler != null &&
295295
(ReferenceEquals(_originalHandler.Target, handler) ||
296-
_originalHandler.Target is PropertyChangedEventHandler eventHandler &&
296+
(_originalHandler.Target is PropertyChangedEventHandler eventHandler &&
297297
handler is PropertyChangedEventHandler &&
298298
Equals(
299299
eventHandler.Target,
300-
(handler as PropertyChangedEventHandler)?.Target));
300+
(handler as PropertyChangedEventHandler)?.Target)));
301301
}
302302
}
303303

src/ReactiveUI/Platforms/uap10.0.16299/WinRTAutoSuspendApplication.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ namespace ReactiveUI
2020
/// <summary>
2121
/// AutoSuspend-based Application. To use AutoSuspend with WinRT, change your
2222
/// Application to inherit from this class, then call:
23-
///
24-
/// Locator.Current.GetService.<ISuspensionHost>().SetupDefaultSuspendResume();
23+
/// Locator.Current.GetService.&lt;ISuspensionHost&gt;().SetupDefaultSuspendResume();
24+
/// This will register your suspension host.
2525
/// </summary>
2626
public class AutoSuspendHelper : IEnableLogger
2727
{
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
7+
namespace ReactiveUI
8+
{
9+
/// <summary>
10+
/// Encapsulates a user action behind a reactive interface.
11+
/// This is for interop inside for the command binding.
12+
/// Not meant for external use due to the fact it doesn't implement ICommand
13+
/// to force the user to favor the Reactive style command execution.
14+
/// </summary>
15+
internal interface IReactiveCommand : IDisposable, IHandleObservableErrors
16+
{
17+
/// <summary>
18+
/// Gets an observable whose value indicates whether the command is currently executing.
19+
/// </summary>
20+
/// <remarks>
21+
/// This observable can be particularly useful for updating UI, such as showing an activity indicator whilst a command
22+
/// is executing.
23+
/// </remarks>
24+
IObservable<bool> IsExecuting { get; }
25+
26+
/// <summary>
27+
/// Gets an observable whose value indicates whether the command can currently execute.
28+
/// </summary>
29+
/// <remarks>
30+
/// The value provided by this observable is governed both by any <c>canExecute</c> observable provided during
31+
/// command creation, as well as the current execution status of the command. A command that is currently executing
32+
/// will always yield <c>false</c> from this observable, even if the <c>canExecute</c> pipeline is currently <c>true</c>.
33+
/// </remarks>
34+
IObservable<bool> CanExecute { get; }
35+
}
36+
}

0 commit comments

Comments
 (0)