Git Product home page Git Product logo

mvvm's Issues

CanExecute not firing on OnCanExecuteChanged()

Hi Stephen,

I tried the AsyncCommand in a Xamarin Forms project and saw strange behavior.

  • I do supply the CanExecute to the AsyncCommand constructor
  • I can see that it does get invoked once
  • When my properties in the ViewModel change I invoke OnCanExecuteChanged()

Problem :
I expected my canExecute delegate to be invoked but it does not.

I read the source code of AsyncCommand and then traversed up the chain in Mvvm.Core to see the implementation of WeakCanExecuteChanged. Everything looks fine.

I then copied your AsyncCommand implementation locally, renamed it but still kept the same implementation i.e. it relies on WeakCanExecuteChanged from Mvvm.Core. The behavior was still the same.

I then copied your WeakCanExecuteChanged implementation locally, renamed it and used it with AsyncCommand. Still the same behavior. Since now I could debug I can see that OnCanExecuteChanged in WeakCanExecuteChanged is never being invoked.

I then replaced the WeakCollection with a List (essentially not using WeakReferences at all) and then it seemed to work.

I know that the RelayCommand implementation of MvvmLight uses the similar technique of using WeakReference and it does work (it is what I am trying to replace in my relatively larger project with AsyncCommand after reading your excellent articles).

Any suggestions.

Regards & thanks
Kapil

Bind to Execution.Result

Hi, Stephen! Thanks for sharing you thoughts and code on MVVM async.
I tried AsyncCommand pattern in my own project, and a (probably a newb) question arose:
..so, I bind my XAML control to MyAsyncCommand.Execution.Result (where MyAsyncCommand does some time-consuming downloading), and it works almost fine. But! At the time when new command executes, the new Execution object is created, so my bindable control isn't populated with any data until the command completes. And I'd like to have it keeping the old (previously requested) data.

NotifyTask concern

As I mentioned in another post, I'm a fan of NotifyTask. Recently however I noticed, well, not exactly a problem but something unexpected and I would say somewhat inconvenient. I would suggest a change.

The overall design of NotifyTask is that you hand the task in to the constructor, and then you await TaskCompleted. Meanwhile the properties of NotifyTask, such as IsCompleted, IsFaulted, ErrorMessage should be notified by NotifyTask.

But suppose the task being handed in to Create is already faulted? There are a lot of ways this could arise. What will happen is that MonitorTaskAsync will run to completion in the constructor, including NotifyProperties. But since we are still in the constructor of NotifyTask, there are no handlers attached to PropertyChanged at that point. Then when you await TaskCompleted, it returns immediately since the Task that it refers to has already run to completion. Consequently no property notifications will ever be sent.

In effect, the properties of NotifyTask are being initialized to values different from the default value (i.e. some of them are true while the default value for bool is false) but no property notifications occur. This is, I would say, somewhat logical but not at all convenient. We can't just do this:

    asyncExecution = NotifyTask.Create<TOut>( methodAsync() );
    asyncExecution.PropertyChanged += AsyncExecution_PropertyChanged;
    await asyncExecution.TaskCompleted; 

and define a handler

    private void AsyncExecution_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == nameof(NotifyTask.InnerException)) {
            this.HandleException( ((NotifyTask)sender).InnerException);
        }
    }

Instead, in addition to doing all the above we also have to test for asyncExecution.InnerException != null after the call to Create. This basically leads to duplicating the logic of the PropertyChanged handler, which is not very desirable from a design point of view.

Also the fact that you have to do this is not very discoverable, as I discovered the hard way!

To remedy this situation my suggestion is to change MonitorTaskAsync as follows:

    private async Task MonitorTaskAsync(Task task)
    {
        try {
            if (task.IsCompleted) {
                await Task.Yield();
            }
            await task;
        } catch {
        } finally {
            NotifyProperties(task);
        }
    }

This way, MonitorTaskAsync will definitely not run to completion. Instead it will always return a meaningful Task that when awaited will do the appropriate NotifyProperties.

Note, this will give you a somewhat different flow of control from the current implementation. The Create call will now always yield while in the past it would only yield if the task was not already completed.

AsyncCommand exceptions and Execution

Just found these classes and they look interesting. However I'm a little puzzled by some specific behaviour that seems contradictory.

In AsyncCommand.ExecuteAsync it explicitly rethrows the cancel/fault state of the original task, such that it propagates out of the ICommand. According to #6 and #17, this change was intentional to make it more like synchronous ICommand implementations, which is fair enough -- at first.

The thing is that if the UI is bound to the command then there is no defence against this becoming an unhandled exception.

With synchronous code, you can put the appropriate logic into your DelegateCommand (or whatever) handler, eg. a try/catch with appropriate actions for cancel and fault.

With asynchronous code, you can do the same thing -- but now you have defeated the purpose of the Execution property -- if you handle the exception at this point then Execution.IsFaulted will never become true and so any UI data-binding you've done to show an error state is useless. If you don't handle the exception at that point, then Execution.IsFaulted is correct but the exception gets rethrown somewhere that you can't catch it again. (Similarly for cancel.)

There's a little bit of a catch-22 -- if you do swallow exceptions and rely on people binding to Execution then people might be confused if they forget to do that and the exception just "vanishes". But if you don't, then Execution itself seems useless because it will never report anything other than success (or you get unhandled exceptions).

Perhaps the model to consider here is not ICommand, but AsyncOperation/BackgroundWorker. These are async and they do swallow exceptions (by reporting them in the RunWorkerCompleted handler and nowhere else). It seems to me that AsyncCommand.Execution better fits that model (since Task itself is similar).

Either that or there needs to be some way to inject some user-specified exception handling code around that await but still inside AsyncCommand.ExecuteAsync.

_canExecuteChanged = new WeakCanExecuteChanged(this) in AsyncCommand

I created an Mvvm.AsyncCommand and bound it as the Command of a button.
I got a null pointer exception in CanExecuteChanged_add, the _canExecuteChanged variable is null.

I am not sure how to use the class. I can set the CanExecuteChanged property to assign a WeakReference-based handler. However I don't see how to trigger CanExecute=false during execaution of the command. If I call OnCanExecuteChanged before or after the command executes then it will not accomplish the objective of setting CanExcecute=false during the execution.

The class itself does not trigger CanExecuteChanged as part of Execute, so it does not set CanExecute=false during Execute.

Looking at the derived class, the use of "new" for OnCanExecuteChanged is striking. While there are some situations where "new" is a necessary design element, in most cases it should be avoided. This is because it means that a different method will be called if a derived pointer is used vs if a base pointer to the very same object is used. That behavior is not what one usually expects -- normally there is only one version of a given method for a given object.

Steve

PS I find it confusing is that there is another AsyncCommand, with a very different implementation, in StephenCleary / AsyncEx. It would be a lot easier if each class were in just one package.

Having said that, thanks for some fantastic code!!

Put up release package on nuget.org

Hi Stephen,

is there a chance you can put up a version of this package as release version?
We have been using Nito.AsyncEx version 4.0 for quite some time and recently updated to version 5.0. However this meant to also use this library now, as the NotifyTask got moved into this repo.

We now get build warnings while building our own release packages, because we have to reference a pre-release package.

Thanks for your great work,
Philipp

AsyncCommand<T> ?

Stephen,

Can chance you can update the library to include AsyncCommand ?

Can't capture AsyncCommand exception

Hi Stephen,
I'm trying to use AsyncCommand, this is my example code:

        public AsyncCommand TestCommand
        {
            get
            {
                if (_testCommand == null)
                {
                    _testCommand = new AsyncCommand(
                        async (x) =>
                        {
                            await SaveAsync();
                        });
                }
                return _testCommand;
            }
        }
        private async Task SaveAsync()
        {
            await Task.Delay(1);
            throw new NotImplementedException();
        }

The exception in SaveAsync isn't captured by AsyncCommand.
What is wrong with my code?

Thank you
Giampaolo

NotifyTask - delay in loading data

Hi Stephen,

I am using NotifyTask to load data in a viewmodel constructor in a WPF project but it is taking a few seconds for the data to show on the screen. It is the same using AsyncEx and possibly related to http://stackoverflow.com/questions/29058130/why-does-this-async-method-still-work-on-ui-thread-and-slow-navigation

My viewmodel is basically the code below and I bind the datacontext of a grid to Test.Result.

public class TestViewModel : ViewModelBase
    {
        private readonly ITestService _TestService;
        private int _Id;
        NotifyTask<TestDto> _Test;
        public int Id
        {
            get
            {
                return _Id;
            }

            set
            {
                if (_Id == value)
                {
                    return;
                }

                _Id = value;
                RaisePropertyChanged(() => Id);
            }
        }

        public NotifyTask<TestDto> Test
        {
            get
            {
                return _Test;
            }
            set
            {
                if (_Test == value)
                {
                    return;
                }
                _Test = value;
                RaisePropertyChanged(() => Test);
            }
        }


        public TestViewModel(int id)
        {
            _Id = id;
            _TestService = ServiceLocator.Current.GetInstance<ITestService>();
            Test = NotifyTask.Create(_TestService.GetTest(_Id));
        }

    }

Add constructor overloads with no "parameter" for executeAsync

Most of the time I don't need a parameter for my commands. It would be nice to not have to create my delegates(?) to accept a parameter they'll never use.

I suggest creating a constructor overload:

// This is the current one
AsyncCommand(Func<object, Task> executeAsync, Func<object, bool> canExecute = null)

// This is my suggested overload
AsyncCommand(Func<Task> executeAsync, Func<bool> canExecute = null)

I know Xamarin.Forms has this overload. I haven't tried any other Command implementations yet.

CancelCommand.Wrap does not propagate IsCancelled information

The current version CancelCommand.Wrap() does not propagate IsCancelled information to the Execution.IsCancelled of the parent AsyncCommand.

In the following code

public AsyncCommandsDemoViewModel(IDataClient dataClient)
{
    this.CancelGetData = new CancelCommand();
    this.GetData = new AsyncCommand(
        this.CancelGetData.Wrap(
            async cancellationToken =>
                this.Data = await dataClient.GetDataAsync(cancellationToken)));
}

if the CancelGetData command is executed, GetData.Execuction.IsCancelled never becomes true.

AyncCommand throws on the UI-Thread

The current version of the AsyncCommand rethrows any exception that occurs in the task run by the command.

In the following code

public AsyncCommandsDemoViewModel(IDataClient dataClient)
{
    this.CancelGetData = new CancelCommand();
    this.GetData = new AsyncCommand(
        this.CancelGetData.Wrap(
            async cancellationToken =>
                this.Data = await dataClient.GetDataAsync(cancellationToken)));
}

If the GetDataAsync throws any exception it will be propagated to the UI thread causing the application to crash.

Provide interface for NotifyTask

Hi Stephen,

for unit testing purposes it would be great if NotifyTask (and its generic version) has an interface. This allows mocking of the NotifyTask.

Thanks, Felix

AsyncCommand: How to set CanExecute to a delegate which includes AsyncCommand.Executing

I have a viewmodel for a sign-in form (in Xamarin.Forms). I want the following:

  1. Submit button disabled when text fields are empty or when busy signing in
  2. Text fields deactivated when signing in

Simplified, the viewmodel (which doesn't work properly) is defined like this:

    // skipping INotifyPropertyChanged implementation for user/pass for brevity
    public string Username { get; set; }
    public string Password { get; set; }

    public IAsyncCommand SignInCommand { get; set; }

    public SignInPageModel()
    {
        SignInCommand = new AsyncCommand(SignInAsync, SignInCommandCanExecute);
        PropertyChanged += delegate { ((AsyncCommand) SignInCommand).OnCanExecuteChanged(); };
    }

    private async Task SignInAsync(object _)
    {
        // actual sign-in process here
        await DoSomeWork();
    }

    private bool SignInCommandCanExecute(object _)
    {
        return !string.IsNullOrEmpty(Username) &&
               !string.IsNullOrEmpty(Password) &&
               !((AsyncCommand SignInCommand).Executing;
    }

What I'm mainly wondering is how I should change this to implement requirement 1. When the command is invoked, there is no way I can call OnCanExecuteChanged so that SignInCommandCanExecute returns the correct value. If I call OnCanExecuteChanged just before and after await DoSomeWork() (which is the earliest and latest I can do it AFAIK, at least without mucking around in the UI codebehind), then the command (and the button that binds to it) is disabled just a tad bit late, and not re-enabled at all (because it's still executing as long as SignInAsync is running).

Unless I have missed an obvious solution, I suggest you fix this by calling OnCanExecuteChanged during the command execution process whether or not CanExecute is set when instantiating the AsyncCommand (i.e., https://github.com/StephenCleary/Mvvm.Async/blob/master/src/Nito.Mvvm.Async/AsyncCommand.cs#L126-L127 and later in that method).

Furthermore, for requirement 2, the obvious solution is to bind the text fields' IsEnabled to SignInCommand.Executing. However, the command is of type IAsyncCommand and needs to be cast to AsyncCommand in order to access the Executing property. Do I really have to make a ValueConverter just for this, or is there a simpler/more elegant way?

Calling AsyncCommand.ExecuteAsync from unit test (NUnit 3)

Maybe I've missed something, but I can't get AsyncCommands to work with my tests. As soon as ExecuteAsync is called from a test, an InvalidOperationException is thrown.

   at Nito.Mvvm.ThreadAffinity.VerifyCurrentThread()
   at Nito.Mvvm.StrongCanExecuteChanged.OnCanExecuteChanged()
   at Nito.Mvvm.AsyncCommand.<ExecuteAsync>d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at AsyncCommandNUnit.TestClass.<Throws>d__1.MoveNext() in C:\Projects\AsyncCommandNUnit\AsyncCommandNUnit\TestClass.cs:line 24
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at NUnit.Framework.Internal.AsyncInvocationRegion.AsyncTaskInvocationRegion.WaitForPendingOperationsToComplete(Object invocationResult) in C:\src\nunit\nunit\src\NUnitFramework\framework\Internal\AsyncInvocationRegion.cs:line 113
   at NUnit.Framework.Internal.Commands.TestMethodCommand.RunAsyncTestMethod(TestExecutionContext context) in C:\src\nunit\nunit\src\NUnitFramework\framework\Internal\Commands\TestMethodCommand.cs:line 96

Here's me test code:

    [TestFixture]
    public class TestClass
    {
        [Test]
        public async Task Throws()
        {
            AsyncCommand command = new AsyncCommand(
                async () => { await Task.Delay(1000); });
            await command.ExecuteAsync(null);
        }

        [Test]
        public async Task DoesNotThrow()
        {
            AsyncCommand command = new AsyncCommand(
                () =>
                {
                    Thread.Sleep(1000);
                    return Task.FromResult(0);
                });

            await command.ExecuteAsync(null);
        }

        [Test]
        public async Task AlsoThrows()
        {
            AsyncCommand command = new AsyncCommand(
                () => Task.Delay(1000));

            await command.ExecuteAsync(null);
        }
    }

I've already tried explicitly setting Synchronization context without success. Also I'm experiencing the same behavior when executing similar code in a simple console app.

Here's my environment:

<packages>
  <package id="Nito.Disposables" version="1.2.3" targetFramework="net471" />
  <package id="Nito.Mvvm.Async" version="1.0.0-pre-03" targetFramework="net471" />
  <package id="Nito.Mvvm.Core" version="1.2.2" targetFramework="net471" />
  <package id="NUnit" version="3.10.1" targetFramework="net471" />
  <package id="System.Collections.Immutable" version="1.4.0" targetFramework="net471" />
</packages>

running on Win7

Exceptions vs User Messages

I am a fan of NotifyTask because it clarifies the use of async and how async methods capture exceptions in the returned Task.

One thing I feel could be improved in NotifyTask is to recognize that not all exceptions are the same. Some exceptions indicate a system problem (e.g. file system error, network down, etc), while others indicate a program or programmer error (e.g. ArgumentException).

NotifyTask promotes the use of exceptions for user message by providing the bindable ErrorMessage property. It is not that common to use exceptions for user messages because (a) exceptions frequently are not localized or are in other ways not user-friendly and (b) user messages are considered to be "normal" rather than "exceptional" and (c) if you use exceptions for user messages then you have to have a way of distinguishing user-message exceptions from system and programmer errors.

If a system or programmer error occurs, then I want NotifyTask to propagate the exception so that I am forced to deal with the exception. On the other hand if the exception represents a user message then I want NotifyTask to capture the exception and put it into ErrorMessage so that I can show it at a convenient time / place in the user interface.

This is quite easily accomplished by adding enum NotifyTaskExceptions { RethrowAll, RethrowNone, RethrowAllButUserInformationExceptions, RethrowUserInformationExceptionsOnly } and then using it in MonitorTaskAsync to test whether the exception should be rethrown. This provides flexibility with respect to either propagating or capturing exceptions. I am attaching the revised code.

In general, however, my suggestion is that async user notifications should be managed without the use of exceptions, because this avoids the issues (a, b, c) above. The worker/async function in the Model or in a service should be able to provide a progress report and this should then result in PropertyChanged on an object in the ViewModel. One way to handle this, promoted for example in MvvmLight, is to use a Messenger service: post a message from the Model or from the service, and have the ViewModel or the View listen for and apply the message. I am not a fan of this approach because is requires creating a new infrastructure/paradigm of messaging, and because messaging does not by itself directly solve the problem of getting status information from the Model or service to a PropertyChanged event. In addition this approach creates the problem of how to ensure that messages notifying the start of work are always matched by messages notifying the end of work.

My suggestion in this regard is to have a ProgressReport class which is handed in to the worker/async function, much in the same way that a CancellationToken is handed in. ProgressReport should implement INotifyPropertyChanged. By updating the ProgressReport, the worker/async function provides status information, which is then translated into PropertyChanged events by the ProgressReport. Obviously one has to look out for thread safety and for the fact that the PropertyChanged notification may need to be marshalled onto the UI thread. I am attaching a ProgressReport implementation which does this. The fields in the ProgressReport are designed to be convenient for the ProgressBar and ProgressRing UI controls. There is also an Activate function designed to be used in a "using" block so that the worker/async function definitely notifies when work is complete.

ProgressReport uses a NotifyBase class which takes care of marshalling the PropertyChanged onto the UI thread. There is also an additional Property class in there which lets you use lambda notation for property names -- so that the compiler checks the property names -- I got that part off a blog somewhere, unfortunately I forget the reference.

I am aware of IProgress, however this is too limited to address the issues above and also is not well suited to ProgressRing and ProgressBar.

I am hereby entering the attached code into the public domain for use by anyone without restriction.

NotifyTask.txt
ProgressReport.txt
NotifyBase.txt
Property.txt

Hmmm, forgot this:

public partial class UserInformationException: Exception
{
    public UserInformationException() { }

    public UserInformationException(string message) : base(message) { }

    public UserInformationException(string message, Exception innerException) : base(message, innerException) { }
}

}

AsyncCommand updates CanExecute somewhat late and/or not at all

Not sure why this is happening, but I can't figure it out.

My command is defined like this:

public AsyncCommand ToggleCheckedCommand { get; }

// constructor
public MyViewModel()
{
    ToggleCheckedCommand = new AsyncCommand(ToggleCheckedAsync);
}

private async Task ToggleCheckedAsync(object _)
{
    var response = await ServerApi.DoWebRequestAsync();
    if (response.Success)
        ...
}

If I debug the app and break at await ServerApi.DoWebRequestAsync(), and mouseover ToggleCheckedCommand, Execution is null and IsExecuting is False. If I perform the web request and continue to the next line, if (response.Success), Execution and IsExecuting assume the expected values.

If I unit test my viewmodel and mock ServerApi, so that it returns instantly, Execution is null and IsExecuting is False throughout the test (as seen when debugging and breaking at the same lines). This makes the test fail, since I'm checking for whether or not the command is disabled during execution.

Is this something you can reproduce? Using v1.0.0-eta-02.

Package release/prerelease status

Hi Stephen,

Firstly, thanks for all of the helpful resources you have produced over the years regarding how to best incorporate asynchronous programming into WPF/MVVM applications. They have been extremely helpful, especially as the combination of WPF, MVVM, and async/await seems to be something that there is no "perfect" solution for.

Next, apologies if creating an issue wasn't the right thing to do here, as all I really have is a quick question regarding the status of this NuGet package:

I am mainly interested in using the NotifyTask type (basically for the same reason as this question) but was just wondering if there is a specific reason why you haven't moved this package out of its "prerelease" state yet? Should I take that to mean it's not "prod ready"?

Thanks again,

Adam

Provide stable release of Nito.Mvvm.Async

Hi Stephen,

thanks for this great library! Currently Nito.Mvvm.Async is only available with version 1.0.0.pre04, with no updates in the last years. Is it possible to provide a stable version from it? Or are the functionalities provided with another package?

Thanks in advance!

Additional CancelCommand.WrapDelegate for parameter-less delegate

For when you have a delegate that only has a cancellation token:

public Func<Task> WrapDelegate(Func<CancellationToken, Task> executeAsync)
{
     return async () =>
     {
          using (StartOperation())
               await executeAsync(CancellationToken);
     };
}

I've implemented an extension method for my own purposes, but thought it would be nice for it to be in the CancelCommand class.

Async command examples

Hi Stephen,

This really is not an issue it's just a discussion about usage of AsyncCommand in general.

I really loved your MSDN magazine articles about this subject. They are awesome. You really explained your thought process while creating NotifyTask and AsyncCommand classes. Problem with this version on GitHub is considerable difference than your last explained version. I would really love to see your thought process while designing this class.
Another issue is cancellation. I am not sure what would be the proper way of "connecting" Async and Cancel commands. I did tried to use something like this in ViewModel constructor (same example like you used in your MSDN article):
CancelCountCommand = new CancelCommand();
CountUrlBytesCommand = new AsyncCommand.v2.AsyncCommand(async (param) => ByteCount = await TestService.DownloadAndCountBytesAsync(Url, CancelCountCommand.CancellationToken));

But the problem with this solution is that Cancel button is enabled by default. Canceling works only first time and if user tries to start AsyncCommand again, it fails saying that Task is canceled. How should I use it properly?

Thank you,
Milos

CancelCommand WrapDelegate needs try catch

I get an unhandled TaskCancellationException when cancelling a Command.

I believe you need to add a try catch block to WrapDelegate:

public static Func<object, Task> WrapDelegate(Func<object, CancellationToken, Task> executeAsync)
        {
            return async () =>
            {
                using (StartOperation())
                {
                    try
                    {
                        await executeAsync(CancellationToken);
                    }
                    catch
                    {
                    }
                }
            };
        }

Task exceptions not "handled"

I finally have a good repro for this problem. If you take the code you published for the MSDN article, everything works correctly. If you then remove the code duplicated by this library and add the prerelease NuGet reference to this library then task based exceptions make it all the way up to unhandled exceptions.
AsyncCommands3.zip

Let me know if there are any questions

AsyncCommand.ExecuteAsync null check error

AsyncCommand.ExecuteAsync checks if _canExecute is null, but I believe it means to check if it is not null:

public override async Task ExecuteAsync(object parameter)
        {
            Execution = NotifyTask.Create(_executeAsync(parameter));
            if (_canExecute != null)
                base.OnCanExecuteChanged();
            var propertyChanged = PropertyChanged;
            propertyChanged?.Invoke(this, PropertyChangedEventArgsCache.Instance.Get("Execution"));
            propertyChanged?.Invoke(this, PropertyChangedEventArgsCache.Instance.Get("IsExecuting"));
            await Execution.TaskCompleted;
            if (_canExecute != null)
                base.OnCanExecuteChanged();
            PropertyChanged?.Invoke(this, PropertyChangedEventArgsCache.Instance.Get("IsExecuting"));
            await Execution.Task;
        }

PropertyChangedEventArgsCache

This isn't really an "issue" more like a question. I did not see a category for general discussion so I am posting it here. I hope that is ok.

I notice you use the PropertyChangedEventArgsCache, when raising PropertyChanged event. I've come across this lazy-caching-the-args approach elsewhere in implementations of INotifyPropertyChanged. My understanding is that this is to avoid slamming the garbage collector with too many allocations when the property changes really fly. Is my understanding correct?

Because using this also means that you must lock the the global cache lock every single time you want to raise aPropertyChanged for any client that uses it. Is that really better? Has anyone ever done any performance testing on this?

If you know your class might raise many PropertyChanged events in a short enough time span to have an effect on performance, then why not simply have static, readonly instances of PropertyChangedEventArgs for those properties inside their owning classes?

.NET 4.0 Target

Hi Stephen,

Is there any implementation of Mvvm.Async targeting .net 4.0?

Curently I am using IAsyncCommand with WPF 4.0 from som implementation I read on your blog about this subject.

However, I am experiencing some ArgumentNullExceptions (Parameter name: task at System.Runtime.CompilerServices.AsyncServices.b__0(Object state) exceptions when the command execution async method returns right away, like this:

`private async Task SaveAsync(CancellationToken token)
{
//Do some validation and decide to return prior to continue method execution
return;
//If OK, do async stuff, returning a task

    }`

As a workaround, if the code await TaskEx.Delay(1) no exception is thrown.

Thank you,

Igor.

AsyncCommand

I have done a bit of work relating to AsyncCommand which I am hoping the community can benefit from.

I had the following objectives and approaches:

  1. To provide built-in support for cancellation, i.e. a bindable Cancel command is provided automatically as part of the AsyncCommand, if a CancellationToken is accepted by the execution delegate.
  2. To provide built-in support for progress notification. This was accomplished using the bindable ProgressReport class referenced in my other post.
  3. To allow a variety of execution delegates -- whether async or sync, and allowing any combination of CancellationToken, ProgressReport, or command parameter object as an input to the execution delegate. This was achieved by having a number of constructors which take the various possible execution delegates and convert them privately into a unified form.
  4. To be able to execute the delegate either on the current thread (await execution(...)) or on a different thread (await Task.Run(()=>execution(...))). The latter is suitable for executing CPU-bound synchronous tasks in the background. It is captured by a boolean property, RunOnDifferentThread.
  5. To move away from the CanExecute paradigm toward something more up-to-date, i.e. consistent with property notifications. This was accomplished by allowing the user to bind a boolean function (updated by property notifications) with the meaning that the command can execute only if the function is true. Naturally the method in AsyncCommand to set this function is called CanExecuteOnlyIf( boundFunction). What this does is move us from an async paradigm that requires a lot of special events and handlers to an approach based on binding.
  6. Note: The solution to this problem (5) involved creating a BoundFunction class which defines a function and binds properties to the inputs of the function. When a bound input is updated then the BoundFunction recalculates and provides a PropertyChanged notification for the result. This is a general-purpose class which is useful, for example, in view-models to combine a number of bindable inputs into a bindable output. (The old way of doing this was to use a MultiBinding, which in addition to being awkward also resulted in moving view-model concepts into the view). To support the type-safe binding of properties in code and to have the compiler check the names of property paths, an additional method Property.Path is needed to extract property paths from lambda expressions.
  7. To have a simple way of ensuring that by default a command cannot be executed if it is already executing. This was achieved by creating a boolean property CanExecuteWhileExecuting. An extension of this is to have a way to make a set of commands mutually exclusive, which is captured by calling a method, AreMutuallyExclusive, and passing in the list of mutually exclusive commands. A typical use would be to make, for example, FileNew, FileSave, FileOpen all mutually exclusive.
  8. While the resulting class is somewhat complex, it also provides a high level of functionality. The public footprint is not excessive:
    public bool CanExecuteWhileExecuting { get; set; }
    public static void AreMutuallyExclusive( IEnumerable commands)
    public void CanExecuteOnlyIf(BoundFunction boundFunction)
    public void CanExecuteOnlyIf( Tsrc source, Expression<Func<Tsrc,bool>> propertyPath)
    public NotifyTask Execution
    public bool IsExecuting { get; }
    override public async void Execute(object parameter = null)
    public async Task ExecuteAsync(object parameter)
    public bool RunOnDifferentThread { get; set; }
    public ProgressReport ProgressReport { get; }
    public ICommand CancelCommand { get; }

I am providing source code that accomplishes all this, and I am hereby entering it into the public domain for anyone to use without restriction. Please also refer to my other post discussing NotifyTask and ProgressReport.

sjb

AsyncCommand.txt
BoundFunction.txt
BoundAction.txt
Property.txt

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.