28

有没有人有任何使用 MVVM (Prism) 显示窗口对话框的例子?- 例如,执行命令时的配置设置窗口。

我见过的所有示例都使用了很好的中介模式,但它们也都引用了视图模型中的视图,这并不理想(我们使用的是 DataTemplates)

谢谢

4

6 回答 6

24

我会使用服务来显示对话框。该服务还可以将视图与视图模型链接起来。

public interface IDialogService {
    void RegisterView<TView, TViewModel>() where TViewModel:IDialogViewModel;
    bool? ShowDialog(IDialogViewModel viewModel);
}

public interface IDialogViewModel {
    bool CanClose();
    void Close();
}


RegisterView只是将视图类型与 ViewModel 类型链接起来。您可以在模块初始化中设置这些链接。这比试图让模块在应用程序的顶层注册数据模板更简单。

ShowDialog显示要显示的 ViewModel。就像Window.ShowDialog方法一样,它返回 true、false 和 null 来关闭。该实现只是从您的容器中创建一个新的类型视图TView,将其连接到提供的 ViewModel 并显示它。

IDialogViewModel为 ViewModel 提供一种机制来进行验证并取消对话框的关闭。

我有一个标准的对话窗口,里面有一个内容控件。当ShowDialog被调用时,它会创建一个新的标准对话框,将视图添加到内容控件,连接 ViewModel 并显示它。标准对话框已经有 [OK] 和 [Cancel] 按钮,它们具有适当的逻辑来调用正确的方法IDialogViewModel

于 2009-11-06T06:46:49.667 回答
13

我这样做的方式也是使用中介模式。当 ViewModel 想要显示一个对话框时,它会发送一条消息,该消息由应用程序的主窗口接收。该消息包含对话框使用的 ViewModel 的一个实例。

然后主窗口构造对话框窗口的实例,将视图模型传递给它并显示对话框。对话的结果在原始消息中传回给调用者。

它看起来像这样:

在您的视图模型中:

DialogViewModel viewModel = new DialogViewModel(...);
ShowDialogMessage message = new ShowDialogMessage(viewModel);

_messenger.Broadcast(message);

if (message.Result == true)
{
    ...
}

在主窗口代码隐藏中:

void RecieveShowDialogMessage(ShowDialogMessage message)
{
    DialogWindow w = new DialogWindow();
    w.DataContext = message.ViewModel;
    message.Result = w.ShowDialog();
}

我希望这足以给你这个想法......

于 2009-11-03T17:09:16.663 回答
3

I'm agreed, that using service to display dialog according to MVVM pattern is the most simple solution. But, I also asked myself, if there are 3 assemblies in my project Model, ViewModel, View and according to MVVM pattern assembly ViewModel has a reference to Model, and View to both Model and ViewModel where should I place DialogService class? If I will place one in the ViewModel assembly - I have no chances to create DialogView instance; on the other hand, if I will place DialogService in the View assembly, how I should inject it in my ViewModel class?

So, I would recoment look at Advanced MVVM scenarios with Prism Part: Using Interaction Request Objects

As example of this approach:

DialogViewModelBase

public abstract class DialogViewModelBase : ViewModelBase
{
    private ICommand _ok;

    public ICommand Ok
    {
        get { return _ok ?? (_ok = new DelegateCommand(OkExecute, CanOkExecute)); }
    }

    protected virtual bool CanOkExecute()
    {
        return true;
    }

    protected virtual void OkExecute()
    {
        _isSaved = true;
        Close = true;
    }

    private ICommand _cancel;

    public ICommand Cancel
    {
        get 
        {
           return _cancel ?? (_cancel = new DelegateCommand(CancelExecute, CanCancelExecute));
        }
    }

    protected virtual bool CanCancelExecute()
    {
        return true;
    }

    protected virtual void CancelExecute()
    {
        Close = true;
    }

    private bool _isSaved = false;
    public bool IsSaved
    {
        get { return _isSaved; }
    }

    private bool _close = false;

    public bool Close
    {
        get { return _close; }
        set
        {
            _close = value;
            RaisePropertyChanged(() => Close);
        }
    }
}

CreateUserStoryViewModel:

public class CreateUserStoryViewModel : DialogViewModelBase
{
    private string _name = String.Empty;

    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            RaisePropertyChanged(() => Name);
        }
    }
}

CreateUserStoryRequest

private InteractionRequest<Notification> _createUserStoryRequest;
public InteractionRequest<Notification> CreateUserStoryRequest
{
    get
    {
        return _createUserStoryRequest ?? (_createUserStoryRequest = new InteractionRequest<Notification>());
    }
}

CreateUserStory Command

private void CreateUserStoryExecute()
{
    CreateUserStoryRequest.Raise(new Notification()
    {
        Content = new CreateUserStoryViewModel(),
        Title = "Create User Story"
    }, 
    notification =>
                 {
                      CreateUserStoryViewModel createUserStoryViewModel =
                               (CreateUserStoryViewModel)notification.Content;
                      if (createUserStoryViewModel.IsSaved)
                      {
                         _domainContext.CreateUserStory(
new UserStory(){ Name = createUserStoryViewModel.Name, });
                      }
                 });
}

XAML:

<!--where xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
          xmlns:ir="clr-namespace:Microsoft.Practices.Prism.Interactivity.InteractionRequest;assembly=Microsoft.Practices.Prism.Interactivity"-->

<i:Interaction.Triggers>
  <ir:InteractionRequestTrigger SourceObject="{Binding CreateUserStoryRequest}">
    <ir:PopupChildWindowAction>
      <ir:PopupChildWindowAction.ChildWindow>
        <view:CreateUserStory />
      </ir:PopupChildWindowAction.ChildWindow>
    </ir:PopupChildWindowAction>
  </ir:InteractionRequestTrigger>
</i:Interaction.Triggers>
于 2011-11-16T20:33:45.077 回答
2

正如我理解您上面的评论一样,问题不在于显示对话框,而在于隐藏它们。有两种方法可以解决这个问题:

  1. 使用标准对话窗口来实现视图。这将需要在 View 和 ViewModel 之间有一种松散耦合的通信方式,以便 ViewModel 可以通知 View 可以在不引用视图的情况下关闭。

    存在多个允许这样做的框架 - Prism 的事件聚合器就是其中之一。在这种情况下,View 将订阅一个事件(例如,MyDialogResultValidated),并且在接收到该事件时,它将相应地设置 DialogResult。如果验证成功,ViewModel(在其 SaveCommand 中)将触发该事件。

  2. 不要使用标准对话框窗口来实现视图。这需要有一个可以有效模拟模态的叠加层。

    在这种情况下,视图和覆盖层的可见性将绑定 ViewModel 的 IsVisible 属性,该属性将由 SaveCommand 实现相应地设置,或者在 ViewModel 需要显示视图时进行设置。

第一种方法需要在代码隐藏中添加一些代码,需要添加全局事件,并且(可以说)更少 MVVM-ish。第二种方法需要实现(或使用其他人的实现)覆盖,但不需要在代码隐藏中包含任何代码,不需要全局事件,并且(有争议的)更接近 MVVM .

于 2009-11-04T19:55:00.880 回答
0

It isn't Prism, but this MVVM demo has an Options Dialog that's fully MVVM.

于 2009-11-10T03:33:59.770 回答
0

您可能对以下示例应用程序感兴趣:

http://compositeextensions.codeplex.com

它使用 Prism2 和 PresentationModel(又名 MVVM)模式。示例应用程序包含一个模式对话框。

于 2009-11-03T20:44:48.477 回答