暂停用户输入的viewmodel进程

时间:2011-01-19 08:52:42

标签: mvvm modal-dialog design-patterns

我一直在查看典型的“从viewmodel提升对话框”问题的视图示例,注意到3个主要解决方案:

  • 使用附加行为
  • 使用中介模式
  • 使用服务

我有点陷入困境,并努力找到一个容易融入我的问题空间的解决方案 - 这是一个非常简单的文件复制问题:

  • 我的viewmodel正在处理循环(复制文件列表)
  • 当目标文件已经存在时,我需要提出一个模态对话框以获得确认替换
  • vm需要等待并接收确认才能继续
  • 根据http://www.codeproject.com/KB/WPF/wpfmodaldialog.aspx,“模态对话框”实际上不是新窗口,而是我的MainWindow中隐藏的叠加层(感谢Ronald!)

我主要在那里,但我遇到的最大困难是: - 如何在等待输入时暂停viewmodel中的循环 - 如何将输入返回到循环内的viewmodel,以便它可以继续

到目前为止,我倾向于服务解决方案,因为它似乎是一个直接的方法调用,返回vm必须等待。但是,它确实意味着服务需要直接绑定到视图以使元素可见?

如果有人可以发布一些直接处理这个问题的简单代码,我(和网)会非常高兴!谢谢!

1 个答案:

答案 0 :(得分:0)

例如,您有一个名为IDialogService的服务,其中包含以下界面:

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

正如您所提到的,为了使服务能够显示实际的对话框,它需要引用将显示实际覆盖元素的视图。但是我不想直接引用视图,而是通过接口引用它。让我们称之为ICanShowDialog,它将拥有以下成员:

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

此界面将由拥有对话框叠加层的视图(例如您的主窗口)实现。

现在有趣的部分:在显示对话框时暂停代码执行。首先,我建议你不要使用覆盖元素,但如果可能的话使用常用的窗口。那你就没有那个问题了。您可以设置对话框窗口的样式,使其看起来就像叠加元素一样。 无论如何,如果您仍然想使用overlay元素,那么您可以执行以下技巧来暂停代码执行:

以下是ConfirmAction inteface的IDialogService方法的伪代码:

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;
}

以下是DispatcherUtils.DoEvents()的代码(取自此处: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); 
   }
}

但我必须警告你。使用DoEvents可能会导致内部调度程序循环导致的一些细微错误。

作为在显示对话框时暂停代码执行的替代方法,您可以使用回调:

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

但使用它不会那么方便。