Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM Light Call async method on property changed?

So I've been doing quite a bit of digging and I haven't been able to find any real definitive answer to this anywhere.

I'm writing an application using MVVM Light and WPF. I have a service that is injected into my ViewModel that checks the validity of a certain property that is set. The service makes a web-call, and it is asynchronous. The call does not need to halt execution of the application, and it's solely to provide visual feedback to the user as to the validity of the entered value.

As such, I've managed to hack something together to get it to work, but it feels somewhat hackey.

What is the proper way to execute an asynchronous method on a property change without resorting to something like async void?

Here's what I currently have.

    public string OmmaLicenseNumber
    {
        get => _ommaLicenseNumber;
        set
        {
            Set(() => OmmaLicenseNumber, ref _ommaLicenseNumber, value);
            Patient.OmmaLicenseNumber = value;

            var _ = CheckLicenseValid();
        }
    }

    private async Task CheckLicenseValid()
    {
        var valid = await _licenseValidationService.IsValidAsync(OmmaLicenseNumber);

        // We don't want the UI piece showing up prematurely. Need 2 properties for this;
        LicenseValid = valid;
        LicenseInvalid = !valid;
    }

If I simply attempt to call .Result on The async method, it results in a deadlock that requires an application restart to fix. And while what I have works, I'm not really a fan. What are my other options?

like image 568
JD Davis Avatar asked Jan 27 '23 13:01

JD Davis


1 Answers

Event handlers allow for the use of async void

Reference Async/Await - Best Practices in Asynchronous Programming

public string OmmaLicenseNumber {
    get => _ommaLicenseNumber;
    set {
        Set(() => OmmaLicenseNumber, ref _ommaLicenseNumber, value);
        Patient.OmmaLicenseNumber = value;
        //Assuming event already subscribed 
        //i.e. OmmaLicenseNumberChanged += OmmaLicenseNumberChanged;
        OmmaLicenseNumberChanged(this, 
            new LicenseNumberEventArgs { LicenseNumber = value }); //Raise event
    }
}

private event EventHandler<LicenseNumberEventArgs> OmmaLicenseNumberChanged = delegate { };
private async void OnOmmaLicenseNumberChanged(object sender, LicenseNumberEventArgs args) {
    await CheckLicenseValid(args.LicenseNumber); //<-- await async method call
}

private async Task CheckLicenseValid(string licenseNumber) {
    var valid = await _licenseValidationService.IsValidAsync(licenseNumber);

    // We don't want the UI piece showing up prematurely. Need 2 properties for this;
    LicenseValid = valid;
    LicenseInvalid = !valid;
}

//...

public class LicenseNumberEventArgs : EventArgs {
    public string LicenseNumber { get; set; }
}

Do I think this to be a little heavy handed?

Yes. This is just meant as an example to show that it is doable.

Can this be refactored to some simpler helper/utility method call?

Yes. Could look a lot like an awaitable callback pattern using expressions to get value to validate

like image 65
Nkosi Avatar answered Jan 29 '23 03:01

Nkosi