0

I am using MahApps and I am trying to implement an abort-dialog if a user cancels a print-process. Since I am still using .Net 4.0 I cannot use await, but need to use continuations as stated here:

However for the life of me I cannot figure out how to do this. I have created a class DialogService that I want to use to present dialogs, when needed. I added the method AbortPrintingDialog(ViewModelBase parentViewModel), where parentViewModel is the ViewModel that wants to show the dialog. Originally I had the following for AbortPrintingDialog, which is an adaption of code from the MahApps sample program and works as expected giving the correct output on the debug-console:

public class DialogService
{
    private IDialogCoordinator dialogCoordinator;

    public DialogService(IDialogCoordinator dialogCoordinator)
    {
        this.dialogCoordinator = dialogCoordinator;
    }

    public void AbortPrintingDialog(ViewModelBase parentViewModel)
    {
        dialogCoordinator.ShowMessageAsync(parentViewModel,
                        "Abort Printing",
                        "Printing is in progress. Are you sure you want to abort the printing process?",
                        MessageDialogStyle.AffirmativeAndNegative).ContinueWith(t => { Debug.WriteLine("t.Result: " + t.Result); });
    }
}

I now tried to change this using continuations so that I can get the user-selected value in order to return it later on from my function AbortPrintingDialog. So I modified AbortPrintingDialog like this, which I thought would work after reading the code on this MSDN page:

public MessageDialogResult AbortPrintingDialog(ViewModelBase parentViewModel)
{
    Task<MessageDialogResult> WaitUserInputTask = dialogCoordinator.ShowMessageAsync(parentViewModel,
                        "Abort Printing",
                        "Printing is in progress. Are you sure you want to abort the printing process?",
                        MessageDialogStyle.AffirmativeAndNegative);
    Task.WaitAll(WaitUserInputTask);
    Task<MessageDialogResult> continuation = WaitUserInputTask.ContinueWith((antecedent) =>
     {
         return antecedent.Result;
     });

    return continuation.Result;
}

However, now when I hit the abort-button in my GUI to call AbortPrintingDialog, the GUI locks up and I don't get any error-message. So what am I doing wrong? I have been trying to figure this out and fiddling around for quite for some time now...

packoman
  • 1,230
  • 1
  • 16
  • 36
  • Not clear what are you trying to do. You said "return user-selected value from AbortPrintingDialog" but in your example it retuns void. Your UI is blocking because of Task.WaitAll(WaitUserInputTask) by the way - don't do this. – Evk May 27 '16 at 17:48
  • @Evk Sorry for not clearly stating my question. I have changed the second definition of `AbortPrintingDialog` to better reflect my goal. Essentially, I want to wait inside `AbortPrintingDialog` until the user has made his selection and then return that result from `AbortPrintingDialog`. It is my understanding that this can easily be done using the `await` statement, but I don't know how to achieve this with a continuation (if at all possible). If there is another way to achieve this that would do too. Thanks again. – packoman May 28 '16 at 19:23
  • You don't need to return MessageDialogResult. Instead, return Task and use ContinueWith to register actions to be done when user made his choice. – Evk May 28 '16 at 21:01
  • @Evk Ok. So there is no other way of doing this? Like I said, I way hoping to avoid this functional style of programming and stay with the more familiar way (to me) of doing this. E.g. using something like `await` seems more clean and intuitive. Anyway thanks for your time. If you hack up a quick example that I can accept as the answer, I will do that. – packoman May 29 '16 at 09:41

1 Answers1

1

I'll try to explain a bit why you cannot do it exactly as you want to. First, why your code deadlocks. When user made a choice and some internal code in dialogCoordinator.ShowMessageAsync needs to continue - it does that on UI (user interface) thread. But you already blocked UI thread - you are waiting on it when dialogCoordinator.ShowMessageAsync will be completed. So you just cannot wait on UI thread for ShowMessageAsync to complete, because of how that ShowMessageAsync is internally implemented. Of course the developers of this library should have provided you a way to call that method synchronously, but they didn't so you have to live with this.

What are your options then?

  1. Use task continuations. For that you will need to rewrite your code which uses AbortPrintingDialog, but you already know that.
  2. Upgrade to newer framework version and use async\await features.
  3. Install this package and use async\await features in .NET 4.
Evk
  • 98,527
  • 8
  • 141
  • 191