2013-05-10 102 views
2

我正在构建一个基于WPF的销售点系统来练习使用MVVM。 我没有使用任何MVVM框架,代替RelayCommand类文章中的约什 - 史密斯 http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030WPF MVVM设计问题

我以前写的一个,没有(仍然使用WPF)应用MVVM模式。
对于数据库访问,我使用了Entity Framework。它看起来像这样:

我的问题是,我该如何实现这一目标使用MVVM? 首先,我已经写使用MVVM的Login窗口,我的眼前的问题是,

  1. 如何关闭Login窗口(处理它),然后打开MainWindow
  2. 在非MVVM版本中,MainWindow仅包含截屏的顶部部分,即按钮行。
  3. 我是否应该进一步将“按钮栏”拆分为它自己的ViewViewModel,仅使用MainWindow作为将所有内容放在一起的位置?
  4. 如果是这样,我怎么代码,单击按钮时,在“按钮栏”的ViewModel会告诉MainWindowViewModel加载相应的View S(我在非MVVM版本中使用System.Windows.Controls.Page)进入Frame?在非MVVM版本,我使用的代码是相当简单:

    private void btnCheckout_Click(object sender, RoutedEventArgs e) { 
        mainFrame.Navigated += frame_Navigated; 
        var pgCheckout = new pgCheckout(); 
        mainFrame.Navigate(pgCheckout); //The frame 
    } 
    
  5. 如果没有,我怎么加载另一个PageFrame

+0

如果你真的想要遵循一个MVVM模式,那么你确实需要使用其中的一个框架,MVVM和这些框架就像一只手和一只手套一起走到一起,而没有框架留下一个空手套(仍然看起来像一只手但没有真正具有任何手的功能)。 – slugster 2013-05-10 08:44:49

+6

@slugster:不能说我同意。在开始使用MVVM时不使用框架可以加深对模式的理解并了解框架实际为您提供的内容。一旦你了解了MVVM,你就不会觉得你使用框架“欺骗”了,更重要的是,知道如何使用框架更容易。 – 2013-05-10 08:48:58

+0

@KentBoogaart是的,当你这样说的时候你是对的,虽然框架确实有助于纯化(我做了一个没有框架的MVVM应用程序,它并不特别漂亮)。 – slugster 2013-05-10 09:35:34

回答

1

如果你不使用任何现有的框架,你将不得不自己创建一个框架。国际海事组织你可以从中受益,因为你掌控着一切,但你也必须重塑许多事情。 我可以描述我们是如何做到的,无论是对还是错让这里的选票决定:)

首先,你不想污染任何与UI相关的对象的ViewModel代码。但是,ViewModel是关于视图逻辑的,你需要以某种方式控制表示(导航,用户消息...)。 因此,您可以在视图模型中引入某种视图服务来控制与视图相关的逻辑,但不依赖于UI框架中的任何内容。比如说:

public interface IViewService 
{ 
    //show message dialog with message text 
    void ShowMessageDialog(string message); 
    //show Yes/No message dialog with message text. Retrun true if answer is Yes 
    bool AskQuestion(string message); 
    //Navigate to some other viewmodel 
    void NavigateTo(ViewModel someOtherViewModel);  
} 

并且您必须使用WPF相关逻辑创建此类服务的具体实现。如何实现这些方法取决于你和你正在使用的UI框架(在这种情况下是WPF)。

在你的viewmodels中,你需要以某种方式获取实现IViewService的对象。您可以使用依赖注入来注入它,使用服务定位器获取实例,甚至可以使用一些硬编码的静态单例实例。 (IMO依赖注入是要走的路,但也使事情更复杂,您需要引入DI容器并使用DI容器创建所有视图模型实例)。

在你的命令中,你可以调用服务的方法。

比方说,你对你的LoginViewModel的LoginCommand(RelayCommand的登录按钮结合)

private void ExecuteLoginCommand(object parameter) 
{ 
     bool loginOk = Login(.....); 
     if(loginOk) 
     viewService.NavigateTo(new MainWindowViewModel); 
     else 
     viewService.ShowMessage("Login failed"); 
} 

最重要的事,视图模型是表现相关的逻辑控制,但不知道UI框架,您的东西。所有的“WPF”代码都在实现IViewService的类中。在你的视图模型中,你“编程接口”,所以你没有与WPF逻辑紧密结合,你的ViewModel是“可测试的”,你甚至可以在其他一些UI平台上重复使用相同的viewmodel代码。

1

解决这些问题的一种方法是创建一个负责加载和卸载视图的单个对象。

在应用程序的开始创建一个实例,该对象将显示一个Window(将显示所有视图),创建ViewModel和View的实例,将View的DataContext设置为ViewModel并将视图传递到窗口,以便它可以显示(例如,设置为网格的子节点)

要关闭视图和/或打开另一个视图:当执行当前ViewModel的命令时,可以发送给同一个对象。该对象可以发信号通知窗口关闭当前视图,并可以以与第一个视图打开相同的方式打开一个新窗口。该命令甚至可以传递一个指示必须加载的ViewModel的参数。

要发送消息,我推荐a MessageBroker that uses weak events来传递消息。如果您不使用弱事件,则应用程序有可能会占用内存,因为事件处理程序会清除垃圾回收。见MVVM Light for such a Messenger

关于你的问题:

  1. 按照上面的步骤。

  2. 和3。是否拆分ViewModels和Views与其他应用程序中的重用和分解有关。

  3. 和5.不要编码点击事件。执行命令传递所需的View,ViewModel以及可能承载View的容器(ContentControl?)。