开发者

pause viewmodel process for user input

I've been looking at a view examples of the typical "raise dialog from viewmodel" problem, noting 3 main solutions:

I'm getting a bit bogged down though and struggling to find a solution that easily fits into my problem space - which is a very simple file copy problem:

  • My viewmodel is processing a loop (copying a list of files)
  • When a file already exists at the destination I need to raise a modal dialog to get confirmation to replace
  • The vm needs to wait for and receive confirmation before continuing
  • The "modal dialog" is actually not a new window but a hidden overlay in my MainWindow, as per http://www.codeproject.com/KB/WPF/wpfmodaldialog.aspx (thanks Ronald!)

I'm mostly there but the biggest struggles I have are: - how to pause the loop in the viewmodel while it waits for input - how to get input back to the viewmodel within the loop so it can carry on

So far I'm leaning towards the service solution because it seems a direct method call with a return that the vm must wait for. However, it does mean the service needs to tie directly to the view in order to make an element visible?

If anyone can post some simple code that deals directly with this problem I (and the net) would be very happy! Thanks!


For example, you have a service called IDialogService with the following interface:

public interface IDialogService
{
   bool ConfirmAction(string title, string confirmationText);
}

As you mentioned, in order for the service to be able to show the actual dialog it needs to have a reference to the view that will show the actual overlay element. But instead of directly referencing the view I prefer to reference it via an interface. Lets call it ICanShowDialog and it will have the following members:

public interface ICanShowDialog
{
   void ShowDialog(object dialogContent);
   void HideDialog();
}

This interface will be implemented by your view that owns the dialog overlay (e.g. your main window).

Now the interesting part: suspending the code execution while the dialog is shown. First of all, I would recommend you not to use overlay elements but use usual windows if possible. Then you will not have that problem. You can style the dialog window so it will look just like the overlay element. Anyway, if you still want to use overlay elements then you can do the following trick to suspend the code execution:

Here is pseudo code of the ConfirmAction method of the IDialogService inteface:

public bool ConfirmAction(string title, string confirmationText)
{
   ConfirmationDialogView dialogView = new ConfirmationDialogView(title, confirmationText);

   DialogShower.ShowDialog(dialogView); // DialogShower is of type ICanShowDialog

   while (!dialogView.ResultAvailable)
   {
      DispatcherUtils.DoEvents();
   }

   DialogShower.HideDialog();

   return dialogView.Result;
}

Here is the code of DispatcherUtils.DoEvents() (that was taken from here: http://dedjo.blogspot.com/2007/08/how-to-doevents-in-wpf.html):

public static class DispatcherUtils
{
   public static void DoEvents()
   {
      DispatcherFrame f = new DispatcherFrame(); 
      Dispatcher.CurrentDispatcher.BeginInvoke(
         DispatcherPriority.Background,  
         (SendOrPostCallback)delegate(object arg) { 
             DispatcherFrame fr =  arg as DispatcherFrame; 
             fr.Continue=True; 
         }, f); 
      Dispatcher.PushFrame(frame); 
   }
}

But I must warn you. Using DoEvents can result in some subtle bugs caused by inner dispatcher loops.

As an alternative to suspending the code execution while a dialog is shown you can use callbacks:

public interface IDialogService
{
   void ConfirmAction(string title, string confirmationText, Action<bool> dialogResultCallback);
}

But it will not be so convenient to use.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜