模态弹出和C#上的MVVM模式下的视图通信

时间:2014-09-12 19:44:39

标签: c# wpf mvvm caliburn.micro modalpopup

我有一个用VB6编码的大型项目,我已经尝试升级到几个月的新技术。我的项目包括在客户端 - 服务器应用程序下重新组合的6个管理模块。来自VB,我的逻​​辑选择是升级到.NET。经过大量研究后,我决定使用C#WPF和MVVM模式(使用Caliburn Micro)。

在开始时我遇到了一些问题,但我设法解决了这些问题。但是现在我已经到了需要(像每个复杂的应用程序)通过模态弹出窗口(或其他一些技术)与不同视图及其相应的viewModel进行通信的点。在这个问题上,MVVM模式似乎非常严格或复杂。一个简单的"您确定要删除此记录(是/否)"是一项非常复杂的任务。因此,我正在寻找建议,因为如何在没有复杂工件的情况下传达视图作为EventAgregators。

到目前为止,我发现唯一可行的替代方法是使用this blog中的ModalContentPresenter类。这个解决方案的问题是:

  • 我需要在同一视图上编写父视图XAML和模态XAML。
  • 我不能从同一视图中获得多个popus。

我想要使用模态弹出窗口的一些示例是:

  • 在视图上放置一个按钮以选择客户端。它应该打开一个包含所有可能客户端的弹出窗口,让用户选择一个。
  • 将产品弹出窗口添加到客户订单。

有任何想法或建议吗?一些示例代码将不胜感激?谢谢!

1 个答案:

答案 0 :(得分:1)

我是关联ModalContentPresenter控件的作者,因此我将尝试解决您的一些问题和疑虑。

  

我需要在同一视图上编写父视图XAML和模态XAML。

您实际上可以在单独的文件中编写两个视图。然后可以使用DataTemplates动态加载视图,这取决于绑定到ViewModelContent属性的ModalContent

参见this,其中描述了可以实现此视图切换的一般方式。

您可以拥有一个MainViewModel,它有两个属性PrimaryViewModelSecondaryViewModel,它们会返回适当的视图模型,这些模型提供主要内容和模态内容的属性和命令。

您可以在XAML中进行以下设置:

<DataTemplate DataType="{x:Type FooViewModel}">
    <Controls:FooView />
</DataTemplate>

<DataTemplate DataType="{x:Type BarViewModel}">
    <Controls:BarView />
</DataTemplate>

<controls:ModalContentPresenter 
              Name="modalPresenter"
              Content={Binding DataContext.PrimaryViewModel}
              ModalContent={Binding DataContext.SecondaryViewModel} />

IsModal属性为false时,只会显示您的PrimaryView。只要您将IsModal属性设置为trueModalContentPresenter就会显示您的SecondaryView

  

我不能从同一视图中获得多个popus。

我认为你的意思是希望能够在同一主视图中显示不同时间的不同模态内容

使用上述技术,这就像切换绑定到ViewModel属性的ModalContent一样简单(通过将IsModal设置为true来显示之前)。只要您DataTemplate绑定了ViewModel(并且MainViewModel正确实施INotifyPropertyChanged),就会显示正确的内容。

  

我想使用模态弹出窗口的一些示例是:

     

在视图上放置一个按钮以选择客户端。它应该打开一个弹出窗口   所有可能的客户,让用户选择一个。

     

将产品弹出窗口添加到客户订单。

一旦您理解了上述技术,您应该能够看到,只要您拥有ViewViewModel对,就可以涵盖您能想到的任何情景。

例如,考虑具有以下接口的viewModels:

public interface SelectCustomerViewModel : INotifyPropertyChanged {
    event EventHandler CustomerSelected;        
    public ObservableCollection<Customer> Customers { get; }
    public Customer Customer { get; set; }
    public Command CustomerSelectedCommand { get; }
}

public interface MainViewModel : INotifyPropertyChanged {
    public SelectCustomerViewModel ModalContent { get; }
    public Command SelectCustomerCommand { get; }
    public bool IsSelectingCustomer { get; }
}

你可以XAML看起来像这样:

<Window x:Class="ModalContentTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Select a customer">

    <DataContext>
        <vm:MainViewModel />
    </DataContext>

    <DataTemplate DataType="{x:Type SelectCustomerViewModel}">
        <Controls:SelectCustomerView />
    </DataTemplate>

    <c:ModalContentPresenter Name="modalPresenter"
                             ModalContent={Binding ModalContent}
                             IsModal={Binding IsSelectingCustomer}>

        <!-- This is the primary content! -->
        <Grid>
            <Button Content="Select a customer"
                    Command={Binding SelectCustomerCommand} />
        </Grid>

    </c:ModalContentPresenter>

</Window>

以下是它的工作原理:

  1. IsSelectingCustomer的{​​{1}}属性将以MainViewModel开头。
  2. 单击主视图中的按钮将调用false对象。然后该命令会告诉SelectCustomerCommandMainViewModel属性更改为IsSelectingCustomer
  3. true将显示数据模板指定的视图。用户现在只能与“选择客户视图”进行交互。
  4. 选择一个客户后,可以点击一个按钮(该按钮绑定到ModalContentPresenter的{​​{1}}),这反过来会引发CustomerSelectedCommand事件。
  5. SelectCustomerViewModel会有一个响应CustomerSelected事件的事件处理程序。然后,处理程序将从MainViewModel读取CustomerSelected属性,最后,它会将SelectedCustomer属性设置为false,从而导致模式内容关闭。