0

I have a button command which sends several emails and therefore takes a few seconds for the method to execute. I want to show a progress ring Mahapps.Metro & disable the view whilst this method is executing.

Here's my ProgressRing in my view:

 <Controls:ProgressRing IsActive="True" Visibility="{Binding IsProgressRingVisible, UpdateSourceTrigger=PropertyChanged}" />

ViewModel property:

  private Visibility _IsProgressRingVisible;
  public Visibility IsProgressRingVisible
   {
     get { return _IsProgressRingVisible; }
     set
      {
        _IsProgressRingVisible = value;
        OnPropertyChanged("IsProgressRingVisible");
      }
    }   

& finally my button command logic:

 private void DisableView()
        {
            IsProgressRingVisible = Visibility.Visible;
            IsEditable = false;
        }

  private void ApprovePublicationCommandAction()
        {
            DisableView();

            try
            {              
                Send emails blah bah

Obviously the command method logic runs before the UI is notified & changes the ProgressRing Visibility. Is there a way I can show the ProgressRing then carry on executing the Command logic?

Nazmul
  • 575
  • 3
  • 18
Hardgraf
  • 2,566
  • 4
  • 44
  • 77
  • What type of a command are you using? RelayCommand by anychance? – Krishna May 22 '15 at 09:53
  • My own implementation that implements the ICommand interface. – Hardgraf May 22 '15 at 09:54
  • 1
    I will post my usage of AsyncRelayCommand see if you can use it in yours – Krishna May 22 '15 at 09:57
  • Great thanks. I've changed my Command method to Async & using await Task.Factory.StartNew(() =>{}); syntax in my try block. All good until I try to send the emails using SmtpClient. Getting an authentication error which I assume is due to me trying to send the emails from another thread... – Hardgraf May 22 '15 at 10:00
  • Please see my answer. You can use the property CommandIsExecuting to hide/show your wait message screen or to disable/enable UI – Krishna May 22 '15 at 10:02
  • Can you wrap your email sending part in a Dispatcher Invoke? See this http://stackoverflow.com/a/1644254/2746905 – Krishna May 22 '15 at 10:05
  • Also please note, that you are violating MVVM pattern. You are having a reference to the view inside your ViewModel. This must be avoided – Tseng May 23 '15 at 14:13
  • No I don't. The view knows nothing of the view model, it is simply binding to an exposed property. What do you mean? – Hardgraf May 26 '15 at 08:44

2 Answers2

2

You can create a Property like CommandIsExecuting and you can bind this property to whenExecuting Action of the command.

Below is code snippet for AsyncRelayCommand ctor

readonly Func<T, Task> _asyncExecute;
        readonly Predicate<T> _canExecute;
        readonly Action<bool> _whenExecuting;
public AsyncRelayCommand(Func<T, Task> asyncExecute, Predicate<T> canExecute, Action<bool> whenExecuting)
        {
            if (asyncExecute == null)
                throw new ArgumentNullException("asyncExecute");

            _asyncExecute = asyncExecute;
            _canExecute = canExecute;
            _whenExecuting = whenExecuting;
        }

and then in your ViewModel where you implement the command you simply use the whenExecuting to your local property like below

    private bool _commandIsExecuting;
    public virtual bool CommandIsExecuting
    {
        get
        { return _commandIsExecuting; }
        protected set
        {
            _commandIsExecuting = value;
            OnPropertyChanged(() => this.CommandIsExecuting);
        }
    }

MyCommand = new AsyncRelayCommand<object>(CommandImplementation, CanIExecute, (b) => CommandIsExecuting = b);
Krishna
  • 1,956
  • 13
  • 25
0

Ended up making my method Async:

private async void ApprovePublicationCommandAction()
{
   DisableView();

   await Task.Factory.StartNew(() =>
    {
      try
       {
         Send emails blah blah

Then enabling the view after the work is complete providing an exception isn't thrown. Thanks for all your help.

Hardgraf
  • 2,566
  • 4
  • 44
  • 77