MVVM: IsBusy and try catch "wrapper" for functions: thoughts? issues?

MarkZhukovskyMarkZhukovsky USMember ✭✭
edited June 2018 in General

I have a ViewModelBase class for my ViewModels and oftentimes found myself having to set IsBusy = true (to trigger an activity indicator to appear in the view) before doing something and then setting it to false afterward, with a try-catch-finally. So I thought it would be nice to write a little helper function that does this for me that I can use in the basic case. I was hoping for some opinions on this, especially if there are any faults I should be aware of. Thanks in advance.

Usage Example:

public ICommand SelectUsersCommand => new Command<string>(SelectUsers);
private void SelectUsers(string userType)
{
    //maybe do something first, then...

    GetBusyWith(() =>
        NavigationService.NavigateToPopupAsync<SelectUsersViewModel>(this, true));
}

or just get busy (!) up front:

public ICommand SelectUsersTestCommand => new Command<string>(param => GetBusyWith(() => SelectUsersTest(param)));
private async Task SelectUsersTest(string userType)
{
    // all of this is wrapped in busy-ness

    // do stuff
    await NavigationService.NavigateToPopupAsync<SelectUsersViewModel>(this, true);
}

ViewModelBase:

   public abstract class ViewModelBase : BindableObject
    {
        private string _title;
        private bool _isBusy;

        protected readonly IDialogService DialogService;
        protected readonly INavigationService NavigationService;
        protected readonly IAnalyticService AnalyticService;

        protected ViewModelBase()
        {
            DialogService = Locator.Instance.Resolve<IDialogService>();
            NavigationService = Locator.Instance.Resolve<INavigationService>();
            AnalyticService = Locator.Instance.Resolve<IAnalyticService>();
        }

        public string Title
        {
            get => _title;
            set => SetProperty(ref _title, value);
        }

        public bool IsBusy
        {
            get => _isBusy;
            set => SetProperty(ref _isBusy, value);
        }

        public async void GetBusyWith(Func<Task> action, [CallerMemberName] string callerName = "", bool trackEvent = false)
        {
            try
            {
                IsBusy = true;

                if (trackEvent)
                    AnalyticService.TrackEvent(callerName);

                await action();
            }
            catch (Exception ex)
            {
                #if DEBUG
                Debug.WriteLine($"{Title ?? ""} - {callerName} Error: {ex}");
                #endif

                await DialogService.ShowAlertAsync("An error ocurred, please try again.", "Error", "Ok");
            }
            finally
            {
                IsBusy = false;
            }
        }

        public async Task<T> GetBusyWith<T>(Func<Task<T>> action, [CallerMemberName] string callerName = "", bool trackEvent = false)
        {
            try
            {
                IsBusy = true;

                if (trackEvent)
                    AnalyticService.TrackEvent(callerName);

                return await action();
            }
            catch (Exception ex)
            {
                #if DEBUG
                Debug.WriteLine($"{Title ?? ""} - {callerName} Error: {ex}");
                #endif

                await DialogService.ShowAlertAsync("An error ocurred, please try again.", "Error", "Ok");
            }
            finally
            {
                IsBusy = false;
            }

            return default(T);
        }

        public virtual Task InitializeAsync(object navigationData)
        {
            return Task.FromResult(false);
        }

        protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = "")
        {
            if (EqualityComparer<T>.Default.Equals(storage, value))
                return false;
            storage = value;
            this.OnPropertyChanged(propertyName);
            return true;
        }
    }
Sign In or Register to comment.