diff --git a/MvvmHelpers.UnitTests/AsyncCommandTests.cs b/MvvmHelpers.UnitTests/AsyncCommandTests.cs new file mode 100644 index 0000000..785ffc0 --- /dev/null +++ b/MvvmHelpers.UnitTests/AsyncCommandTests.cs @@ -0,0 +1,179 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MvvmHelpers.Commands; +using System; +using System.Threading.Tasks; + +namespace MvvmHelpers.UnitTests +{ + [TestClass] + public class AsyncCommandTests + { + #region Events + protected event EventHandler TestEvent + { + add => TestWeakEventManager.AddEventHandler(value); + remove => TestWeakEventManager.RemoveEventHandler(value); + } + #endregion + + #region Properties + protected const int Delay = 500; + protected WeakEventManager TestWeakEventManager { get; } = new WeakEventManager(); + #endregion + + #region Methods + protected Task NoParameterTask() => Task.Delay(Delay); + protected Task IntParameterTask(int delay) => Task.Delay(delay); + protected Task StringParameterTask(string text) => Task.Delay(Delay); + protected Task NoParameterImmediateNullReferenceExceptionTask() => throw new NullReferenceException(); + protected Task ParameterImmediateNullReferenceExceptionTask(int delay) => throw new NullReferenceException(); + + protected async Task NoParameterDelayedNullReferenceExceptionTask() + { + await Task.Delay(Delay); + throw new NullReferenceException(); + } + + protected async Task IntParameterDelayedNullReferenceExceptionTask(int delay) + { + await Task.Delay(delay); + throw new NullReferenceException(); + } + + protected bool CanExecuteTrue(object parameter) => true; + protected bool CanExecuteFalse(object parameter) => false; + protected bool CanExecuteDynamic(object booleanParameter) => (bool)booleanParameter; + #endregion + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void AsyncCommand_NullExecuteParameter() + { + //Arrange + + //Act + + //Assert + new AsyncCommand(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void AsyncCommandT_NullExecuteParameter() + { + //Arrange + + //Act + + //Assert + new AsyncCommand(null); + } + + [TestMethod] + public async Task AsyncCommand_ExecuteAsync_IntParameter_Test() + { + //Arrange + AsyncCommand command = new AsyncCommand(IntParameterTask); + + //Act + await command.ExecuteAsync(500); + await command.ExecuteAsync(default); + + //Assert + + } + + [TestMethod] + public async Task AsyncCommand_ExecuteAsync_StringParameter_Test() + { + //Arrange + AsyncCommand command = new AsyncCommand(StringParameterTask); + + //Act + await command.ExecuteAsync("Hello"); + await command.ExecuteAsync(default); + + //Assert + + } + + [TestMethod] + public void AsyncCommand_Parameter_CanExecuteTrue_Test() + { + //Arrange + var command = new AsyncCommand(IntParameterTask, CanExecuteTrue); + + //Act + + //Assert + Assert.IsTrue(command.CanExecute(null)); + } + + [TestMethod] + public void AsyncCommand_Parameter_CanExecuteFalse_Test() + { + //Arrange + var command = new AsyncCommand(IntParameterTask, CanExecuteFalse); + + //Act + + //Assert + Assert.IsFalse(command.CanExecute(null)); + } + + [TestMethod] + public void AsyncCommand_NoParameter_CanExecuteTrue_Test() + { + //Arrange + var command = new AsyncCommand(NoParameterTask, CanExecuteTrue); + + //Act + + //Assert + Assert.IsTrue(command.CanExecute(null)); + } + + [TestMethod] + public void AsyncCommand_NoParameter_CanExecuteFalse_Test() + { + //Arrange + var command = new AsyncCommand(NoParameterTask, CanExecuteFalse); + + //Act + + //Assert + Assert.IsFalse(command.CanExecute(null)); + } + + + [TestMethod] + public void AsyncCommand_CanExecuteChanged_Test() + { + //Arrange + bool canCommandExecute = false; + bool didCanExecuteChangeFire = false; + + var command = new AsyncCommand(NoParameterTask, commandCanExecute); + command.CanExecuteChanged += handleCanExecuteChanged; + + void handleCanExecuteChanged(object sender, EventArgs e) => didCanExecuteChangeFire = true; + bool commandCanExecute(object parameter) => canCommandExecute; + + Assert.IsFalse(command.CanExecute(null)); + + //Act + canCommandExecute = true; + + //Assert + Assert.IsTrue(command.CanExecute(null)); + Assert.IsFalse(didCanExecuteChangeFire); + + //Act + command.RaiseCanExecuteChanged(); + + //Assert + Assert.IsTrue(didCanExecuteChangeFire); + Assert.IsTrue(command.CanExecute(null)); + } + } +} diff --git a/MvvmHelpers.UnitTests/BaseVewModelTests.cs b/MvvmHelpers.UnitTests/BaseVewModelTests.cs index f381ac1..016261b 100644 --- a/MvvmHelpers.UnitTests/BaseVewModelTests.cs +++ b/MvvmHelpers.UnitTests/BaseVewModelTests.cs @@ -1,7 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System.ComponentModel; -namespace MvvmHelpers.Tests +namespace MvvmHelpers.UnitTests { [TestClass] public class BaseViewModelTests diff --git a/MvvmHelpers.UnitTests/CommandTests.cs b/MvvmHelpers.UnitTests/CommandTests.cs new file mode 100644 index 0000000..16e3c9b --- /dev/null +++ b/MvvmHelpers.UnitTests/CommandTests.cs @@ -0,0 +1,261 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using MvvmHelpers.Commands; +using MvvmHelpers.Exceptions; +using System; + +namespace MvvmHelpers.UnitTests +{ + [TestClass] + public class CommandTests + { + [TestMethod] + public void Constructor() + { + var cmd = new Command(() => { }); + Assert.IsTrue(cmd.CanExecute(null)); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void ThrowsWithNullConstructor() + { + new Command((Action)null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void ThrowsWithNullParameterizedConstructor() + { + new Command((Action)null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void ThrowsWithNullCanExecute() + { + new Command(() => { }, null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void ThrowsWithNullParameterizedCanExecute() + { + new Command(o => { }, null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void ThrowsWithNullExecuteValidCanExecute() + { + new Command(null, () => true); + } + + [TestMethod] + public void Execute() + { + bool executed = false; + var cmd = new Command(() => executed = true); + + cmd.Execute(null); + Assert.IsTrue(executed); + } + + [TestMethod] + public void ExecuteParameterized() + { + object executed = null; + var cmd = new Command(o => executed = o); + + var expected = new object(); + cmd.Execute(expected); + + Assert.AreEqual(expected, executed); + } + + [TestMethod] + public void ExecuteWithCanExecute() + { + bool executed = false; + var cmd = new Command(() => executed = true, () => true); + + cmd.Execute(null); + Assert.IsTrue(executed); + } + + [TestMethod] + public void CanExecute() + { + bool canExecuteRan = false; + var cmd = new Command(() => { }, () => { + canExecuteRan = true; + return true; + }); + + Assert.AreEqual(true, cmd.CanExecute(null)); + Assert.IsTrue(canExecuteRan); + } + + [TestMethod] + public void ChangeCanExecute() + { + bool signaled = false; + var cmd = new Command(() => { }); + + cmd.CanExecuteChanged += (sender, args) => signaled = true; + + cmd.RaiseCanExecuteChanged(); + Assert.IsTrue(signaled); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void GenericThrowsWithNullExecute() + { + new Command(null); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void GenericThrowsWithNullExecuteAndCanExecuteValid() + { + new Command(null, s => true); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void GenericThrowsWithValidExecuteAndCanExecuteNull() + { + new Command(s => { }, null); + } + + [TestMethod] + public void GenericExecute() + { + string result = null; + var cmd = new Command(s => result = s); + + cmd.Execute("Foo"); + Assert.AreEqual("Foo", result); + } + + [TestMethod] + public void GenericExecuteWithCanExecute() + { + string result = null; + var cmd = new Command(s => result = s, s => true); + + cmd.Execute("Foo"); + Assert.AreEqual("Foo", result); + } + + [TestMethod] + public void GenericCanExecute() + { + string result = null; + var cmd = new Command(s => { }, s => { + result = s; + return true; + }); + + Assert.AreEqual(true, cmd.CanExecute("Foo")); + Assert.AreEqual("Foo", result); + } + + class FakeParentContext + { + } + + // ReSharper disable once ClassNeverInstantiated.Local + class FakeChildContext + { + } + + [TestMethod] + [ExpectedException(typeof(InvalidCommandParameterException))] + public void CanExecuteReturnsFalseIfParameterIsWrongReferenceType() + { + var command = new Command(context => { }, context => true); + + command.CanExecute(new FakeParentContext()); + } + + [TestMethod] + [ExpectedException(typeof(InvalidCommandParameterException))] + public void CanExecuteReturnsFalseIfParameterIsWrongValueType() + { + var command = new Command(context => { }, context => true); + + command.CanExecute(10.5); + } + + [TestMethod] + public void CanExecuteUsesParameterIfReferenceTypeAndSetToNull() + { + var command = new Command(context => { }, context => true); + + Assert.IsTrue(command.CanExecute(null), "null is a valid value for a reference type"); + } + + [TestMethod] + public void CanExecuteUsesParameterIfNullableAndSetToNull() + { + var command = new Command(context => { }, context => true); + + Assert.IsTrue(command.CanExecute(null), "null is a valid value for a Nullable type"); + } + + [TestMethod] + [ExpectedException(typeof(InvalidCommandParameterException))] + public void CanExecuteIgnoresParameterIfValueTypeAndSetToNull() + { + var command = new Command(context => { }, context => true); + + command.CanExecute(null); + } + + [TestMethod] + public void ExecuteDoesNotRunIfParameterIsWrongReferenceType() + { + int executions = 0; + var command = new Command(context => executions += 1); + + Assert.IsTrue(executions == 0, "the command should not have executed"); + } + + [TestMethod] + public void ExecuteDoesNotRunIfParameterIsWrongValueType() + { + int executions = 0; + var command = new Command(context => executions += 1); + + Assert.IsTrue(executions == 0, "the command should not have executed"); + } + + [TestMethod] + public void ExecuteRunsIfReferenceTypeAndSetToNull() + { + int executions = 0; + var command = new Command(context => executions += 1); + command.Execute(null); + Assert.IsTrue(executions == 1, "the command should have executed"); + } + + [TestMethod] + public void ExecuteRunsIfNullableAndSetToNull() + { + int executions = 0; + var command = new Command(context => executions += 1); + command.Execute(null); + Assert.IsTrue(executions == 1, "the command should have executed"); + } + + [TestMethod] + public void ExecuteDoesNotRunIfValueTypeAndSetToNull() + { + int executions = 0; + var command = new Command(context => executions += 1); + + Assert.IsTrue(executions == 0, "the command should not have executed"); + } + } +} diff --git a/MvvmHelpers.UnitTests/GroupingTests.cs b/MvvmHelpers.UnitTests/GroupingTests.cs index 61c06e9..4177e22 100644 --- a/MvvmHelpers.UnitTests/GroupingTests.cs +++ b/MvvmHelpers.UnitTests/GroupingTests.cs @@ -1,11 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Threading.Tasks; -namespace MvvmHelpers.Tests +namespace MvvmHelpers.UnitTests { [TestClass] public class GroupingTests diff --git a/MvvmHelpers.UnitTests/MvvmHelpers.UnitTests.csproj b/MvvmHelpers.UnitTests/MvvmHelpers.UnitTests.csproj index 7ea7ff7..d4dd9b6 100644 --- a/MvvmHelpers.UnitTests/MvvmHelpers.UnitTests.csproj +++ b/MvvmHelpers.UnitTests/MvvmHelpers.UnitTests.csproj @@ -1,7 +1,8 @@ - + netcoreapp2.0 + 7.3 false diff --git a/MvvmHelpers.UnitTests/ObservableObjectTests.cs b/MvvmHelpers.UnitTests/ObservableObjectTests.cs index ba5448c..1a4297b 100644 --- a/MvvmHelpers.UnitTests/ObservableObjectTests.cs +++ b/MvvmHelpers.UnitTests/ObservableObjectTests.cs @@ -1,10 +1,8 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; using System; using System.ComponentModel; -using System.Linq; -using System.Threading.Tasks; -namespace MvvmHelpers.Tests +namespace MvvmHelpers.UnitTests { [TestClass] public class ObservableObjectTests diff --git a/MvvmHelpers.UnitTests/ObservableRangeTests.cs b/MvvmHelpers.UnitTests/ObservableRangeTests.cs index fcb024e..659b010 100644 --- a/MvvmHelpers.UnitTests/ObservableRangeTests.cs +++ b/MvvmHelpers.UnitTests/ObservableRangeTests.cs @@ -1,10 +1,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; using System.Collections.Specialized; -using System.Linq; -using System.Threading.Tasks; -namespace MvvmHelpers.Tests +namespace MvvmHelpers.UnitTests { [TestClass] public class ObservableRangeTests diff --git a/MvvmHelpers.UnitTests/Person.cs b/MvvmHelpers.UnitTests/Person.cs index de8007e..32771ac 100644 --- a/MvvmHelpers.UnitTests/Person.cs +++ b/MvvmHelpers.UnitTests/Person.cs @@ -1,7 +1,7 @@  using System; -namespace MvvmHelpers.Tests +namespace MvvmHelpers.UnitTests { public class PersonViewModel : BaseViewModel diff --git a/MvvmHelpers.UnitTests/UtilTests.cs b/MvvmHelpers.UnitTests/UtilTests.cs index e39cf6c..d38d337 100644 --- a/MvvmHelpers.UnitTests/UtilTests.cs +++ b/MvvmHelpers.UnitTests/UtilTests.cs @@ -1,10 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace MvvmHelpers.Tests +namespace MvvmHelpers.UnitTests { class UtilTests { diff --git a/MvvmHelpers.UnitTests/WeakEventManagerTests.cs b/MvvmHelpers.UnitTests/WeakEventManagerTests.cs new file mode 100644 index 0000000..ba8189a --- /dev/null +++ b/MvvmHelpers.UnitTests/WeakEventManagerTests.cs @@ -0,0 +1,249 @@ +using Microsoft.VisualStudio.TestTools.UnitTesting; +using System; + +namespace MvvmHelpers.UnitTests +{ + [TestClass] + public class WeakEventManagerTests + { + static int s_count; + + static void Handler(object sender, EventArgs eventArgs) + { + s_count++; + } + + internal class TestSource + { + public int Count = 0; + public TestEventSource EventSource { get; set; } + public TestSource() + { + EventSource = new TestEventSource(); + EventSource.TestEvent += EventSource_TestEvent; + } + public void Clean() + { + EventSource.TestEvent -= EventSource_TestEvent; + } + + public void Fire() + { + EventSource.FireTestEvent(); + } + + + void EventSource_TestEvent(object sender, EventArgs e) + { + Count++; + } + } + + internal class TestEventSource + { + readonly WeakEventManager _weakEventManager; + + public TestEventSource() + { + _weakEventManager = new WeakEventManager(); + } + + public void FireTestEvent() + { + OnTestEvent(); + } + + internal event EventHandler TestEvent + { + add { _weakEventManager.AddEventHandler(value); } + remove { _weakEventManager.RemoveEventHandler(value); } + } + + void OnTestEvent() + { + _weakEventManager.HandleEvent(this, EventArgs.Empty, nameof(TestEvent)); + } + } + + internal class TestSubscriber + { + public void Subscribe(TestEventSource source) + { + source.TestEvent += SourceOnTestEvent; + } + + void SourceOnTestEvent(object sender, EventArgs eventArgs) + { + Assert.Fail(); + } + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void AddHandlerWithEmptyEventNameThrowsException() + { + var wem = new WeakEventManager(); + wem.AddEventHandler((sender, args) => { }, ""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void AddHandlerWithNullEventHandlerThrowsException() + { + var wem = new WeakEventManager(); + wem.AddEventHandler(null, "test"); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void AddHandlerWithNullEventNameThrowsException() + { + var wem = new WeakEventManager(); + wem.AddEventHandler((sender, args) => { }, null); + } + + [TestMethod] + public void CanRemoveEventHandler() + { + var source = new TestSource(); + int beforeRun = source.Count; + source.Fire(); + + Assert.IsTrue(source.Count == 1); + source.Clean(); + source.Fire(); + Assert.IsTrue(source.Count == 1); + } + + [TestMethod] + public void CanRemoveStaticEventHandler() + { + int beforeRun = s_count; + + var source = new TestEventSource(); + source.TestEvent += Handler; + source.TestEvent -= Handler; + + source.FireTestEvent(); + + Assert.IsTrue(s_count == beforeRun); + } + + [TestMethod] + public void EventHandlerCalled() + { + var called = false; + + var source = new TestEventSource(); + source.TestEvent += (sender, args) => { called = true; }; + + source.FireTestEvent(); + + Assert.IsTrue(called); + } + + [TestMethod] + public void FiringEventWithoutHandlerShouldNotThrow() + { + var source = new TestEventSource(); + source.FireTestEvent(); + } + + [TestMethod] + public void MultipleHandlersCalled() + { + var called1 = false; + var called2 = false; + + var source = new TestEventSource(); + source.TestEvent += (sender, args) => { called1 = true; }; + source.TestEvent += (sender, args) => { called2 = true; }; + source.FireTestEvent(); + + Assert.IsTrue(called1 && called2); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void RemoveHandlerWithEmptyEventNameThrowsException() + { + var wem = new WeakEventManager(); + wem.RemoveEventHandler((sender, args) => { }, ""); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void RemoveHandlerWithNullEventHandlerThrowsException() + { + var wem = new WeakEventManager(); + wem.RemoveEventHandler(null, "test"); + } + + [TestMethod] + [ExpectedException(typeof(ArgumentNullException))] + public void RemoveHandlerWithNullEventNameThrowsException() + { + var wem = new WeakEventManager(); + wem.RemoveEventHandler((sender, args) => { }, null); + } + + [TestMethod] + public void RemovingNonExistentHandlersShouldNotThrow() + { + var wem = new WeakEventManager(); + wem.RemoveEventHandler((sender, args) => { }, "fake"); + wem.RemoveEventHandler(Handler, "alsofake"); + } + + [TestMethod] + public void RemoveHandlerWithMultipleSubscriptionsRemovesOne() + { + int beforeRun = s_count; + + var source = new TestEventSource(); + source.TestEvent += Handler; + source.TestEvent += Handler; + source.TestEvent -= Handler; + + source.FireTestEvent(); + + Assert.AreEqual(beforeRun + 1, s_count); + } + + [TestMethod] + public void StaticHandlerShouldRun() + { + int beforeRun = s_count; + + var source = new TestEventSource(); + source.TestEvent += Handler; + + source.FireTestEvent(); + + Assert.IsTrue(s_count > beforeRun); + } + + [TestMethod] + public void VerifySubscriberCanBeCollected() + { + WeakReference wr = null; + var source = new TestEventSource(); + new Action(() => + { + var ts = new TestSubscriber(); + wr = new WeakReference(ts); + ts.Subscribe(source); + })(); + + GC.Collect(); + GC.WaitForPendingFinalizers(); + + Assert.IsNotNull(wr); + Assert.IsFalse(wr.IsAlive); + + // The handler for this calls Assert.Fail, so if the subscriber has not been collected + // the handler will be called and the test will fail + source.FireTestEvent(); + } + } +} diff --git a/MvvmHelpers/Commands/AsyncCommand.cs b/MvvmHelpers/Commands/AsyncCommand.cs index 48f897a..05e53fb 100644 --- a/MvvmHelpers/Commands/AsyncCommand.cs +++ b/MvvmHelpers/Commands/AsyncCommand.cs @@ -16,13 +16,13 @@ namespace MvvmHelpers.Commands public class AsyncCommand : IAsyncCommand { readonly Func execute; - readonly Func canExecute; + readonly Func canExecute; readonly Action onException; bool continueOnCapturedContext; readonly WeakEventManager weakEventManager = new WeakEventManager(); public AsyncCommand(Func execute, - Func canExecute = null, + Func canExecute = null, Action onException = null, bool continueOnCapturedContext = false) { @@ -38,15 +38,13 @@ public event EventHandler CanExecuteChanged remove { weakEventManager.RemoveEventHandler(value); } } - public bool CanExecute() => canExecute?.Invoke() ?? true; + public bool CanExecute(object parameter) => canExecute?.Invoke(parameter) ?? true; public Task ExecuteAsync() => execute(); public void RaiseCanExecuteChanged() => weakEventManager.HandleEvent(this, EventArgs.Empty, nameof(CanExecuteChanged)); #region Explicit implementations - bool ICommand.CanExecute(object parameter) => CanExecute(); - void ICommand.Execute(object parameter) => ExecuteAsync().SafeFireAndForgetAsync(onException, continueOnCapturedContext); #endregion } @@ -57,13 +55,13 @@ public class AsyncCommand : IAsyncCommand { readonly Func execute; - readonly Func canExecute; + readonly Func canExecute; readonly Action onException; bool continueOnCapturedContext; readonly WeakEventManager weakEventManager = new WeakEventManager(); public AsyncCommand(Func execute, - Func canExecute = null, + Func canExecute = null, Action onException = null, bool continueOnCapturedContext = false) { @@ -79,18 +77,17 @@ public event EventHandler CanExecuteChanged remove { weakEventManager.RemoveEventHandler(value); } } - public bool CanExecute(T parameter) => canExecute?.Invoke(parameter) ?? true; + public bool CanExecute(object parameter) => canExecute?.Invoke(parameter) ?? true; public Task ExecuteAsync(T parameter) => execute(parameter); public void RaiseCanExecuteChanged() => weakEventManager.HandleEvent(this, EventArgs.Empty, nameof(CanExecuteChanged)); #region Explicit implementations - bool ICommand.CanExecute(object parameter) => CanExecute((T)parameter); void ICommand.Execute(object parameter) { - if(Utils.IsValidParameter(parameter)) + if(Utils.IsValidParameter(parameter)) ExecuteAsync((T)parameter).SafeFireAndForgetAsync(onException, continueOnCapturedContext); } diff --git a/MvvmHelpers/Commands/Command.cs b/MvvmHelpers/Commands/Command.cs index 4bdb5f1..c6b350c 100644 --- a/MvvmHelpers/Commands/Command.cs +++ b/MvvmHelpers/Commands/Command.cs @@ -15,7 +15,7 @@ public class Command : Command public Command(Action execute) : base(o => { - if (Utils.IsValidParameter(o)) + if (Utils.IsValidParameter(o)) execute((T)o); }) { @@ -28,9 +28,12 @@ public Command(Action execute) public Command(Action execute, Func canExecute) : base(o => { - if (Utils.IsValidParameter(o)) + if (Utils.IsValidParameter(o)) execute((T)o); - }, o => Utils.IsValidParameter(o) && canExecute((T)o)) + }, o => + { + return Utils.IsValidParameter(o) && canExecute((T)o); + }) { if (execute == null) throw new ArgumentNullException(nameof(execute)); diff --git a/MvvmHelpers/Interfaces/IAsyncCommand.cs b/MvvmHelpers/Interfaces/IAsyncCommand.cs index d40aa51..e918bed 100644 --- a/MvvmHelpers/Interfaces/IAsyncCommand.cs +++ b/MvvmHelpers/Interfaces/IAsyncCommand.cs @@ -19,12 +19,6 @@ public interface IAsyncCommand : ICommand /// /// Task to be awaited on. Task ExecuteAsync(); - - /// - /// Method to execute to check if the command can be executed. - /// - /// True if can execute - bool CanExecute(); } /// @@ -38,13 +32,6 @@ public interface IAsyncCommand : ICommand /// Parameter to pass to command /// Task to be awaited on. Task ExecuteAsync(T parameter); - - /// - /// Method to execute to check if the command can be executed. - /// - /// Parameter to pass to command - /// True if can execute - bool CanExecute(T parameter); } } diff --git a/MvvmHelpers/MvvmHelpers.csproj b/MvvmHelpers/MvvmHelpers.csproj index ece2e3b..7bf1ee4 100644 --- a/MvvmHelpers/MvvmHelpers.csproj +++ b/MvvmHelpers/MvvmHelpers.csproj @@ -23,7 +23,7 @@ https://github.com/jamesmontemagno/mvvm-helpers See: https://github.com/jamesmontemagno/mvvm-helpers/blob/master/CHANGELOG.md - default + 7.3 true MvvmHelpers true diff --git a/MvvmHelpers/Utils.cs b/MvvmHelpers/Utils.cs index 5e63085..f2da2a0 100644 --- a/MvvmHelpers/Utils.cs +++ b/MvvmHelpers/Utils.cs @@ -49,12 +49,18 @@ public static async void SafeFireAndForgetAsync(this Task task, Action(object o) { + bool valid; if (o != null) { // The parameter isn't null, so we don't have to worry whether null is a valid option - return o is T; + valid = o is T; + + if (!valid) + throw new InvalidCommandParameterException(typeof(T), null); + + return valid; } var t = typeof(T); @@ -66,10 +72,10 @@ internal static bool IsValidParameter(object o) } // Not a Nullable, if it's a value type then null is not valid - var valid = !t.GetTypeInfo().IsValueType; + valid = !t.GetTypeInfo().IsValueType; if (!valid) - throw new InvalidCommandParameterException(typeof(T), o.GetType()); + throw new InvalidCommandParameterException(typeof(T), null); return valid; }