我正在构建一个基于WPF的销售点系统来练习使用MVVM。
我没有使用任何MVVM框架,而是在Josh Smith的文章中使用了RelayCommand
类
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030
我之前写过一个,没有应用MVVM模式(仍然使用WPF) 对于数据库访问,我使用了Entity Framework。它看起来像这样:
我的问题是,如何使用MVVM实现这一目标?
首先,我已经使用MVVM编写了Login
窗口,我的直接问题是,
Login
窗口(处理它)并打开MainWindow
?MainWindow
仅包含屏幕截图的顶部,即按钮行。View
和ViewModel
,仅使用MainWindow
作为将所有内容放在一起的地方? 如果是这样,我如何编码,当点击按钮时,“按钮栏”的ViewModel
会告诉MainWindow
的{{1}}加载相应的ViewModel
s(我在非MVVM版本中使用View
)进入System.Windows.Controls.Page
?在非MVVM版本中,我使用的代码非常简单:
Frame
如果没有,如何将其他private void btnCheckout_Click(object sender, RoutedEventArgs e) {
mainFrame.Navigated += frame_Navigated;
var pgCheckout = new pgCheckout();
mainFrame.Navigate(pgCheckout); //The frame
}
加载到Page
?
答案 0 :(得分:1)
解决这些问题的一种方法是创建一个负责加载和卸载视图的对象。
在应用程序开始时,将创建此对象的实例,对象将显示一个Window(将显示所有视图),创建ViewModel和View的实例,将View的DataContext设置为ViewModel并将视图传递给窗口以便可以显示(例如,设置为网格的子项)
关闭视图和/或打开另一个视图:当执行当前ViewModel的命令时,可以将消息发送到同一对象。该对象可以通知Window关闭当前视图,并可以打开第一个View的相同方式打开一个新视图。该命令甚至可以传递一个参数,该参数指示必须加载的ViewModel。
要发送消息,我建议a MessageBroker that uses weak events传递消息。如果您不使用弱事件,应用程序将面临占用内存的风险,因为事件处理程序会阻止垃圾回收清理。见MVVM Light for such a Messenger
关于你的问题:
按照上述步骤操作。
和3.是否拆分ViewModel和Views是一个重用和分解的问题,就像在任何其他应用程序中一样。
和5.不要对点击事件进行编码。执行命令传递所需的View,ViewModel以及可能承载View的容器(ContentControl?)。
答案 1 :(得分:1)
如果您不使用任何现有框架,则必须自己创建一个框架。 IMO你可以从中受益,因为你掌控着一切,但你也需要重新发明很多东西。 我可以描述一下我们是如何做到的,无论是对还是错,让这里的选票决定:)
首先,您不希望使用任何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)。
在视图模型中,您需要以某种方式获取实现IViewService
的对象。您可以使用依赖注入注入它,使用服务定位器获取实例,甚至可以使用一些硬编码的静态单例实例。 (IMO依赖注入是可行的方法,但也使事情变得复杂,你需要引入DI容器并使用DI容器创建所有viewmodel实例)。
在您的命令中,您可以调用服务的方法。
假设您的LoginViewModel的LoginCommand(登录按钮绑定的RelayCommand
)
private void ExecuteLoginCommand(object parameter)
{
bool loginOk = Login(.....);
if(loginOk)
viewService.NavigateTo(new MainWindowViewModel);
else
viewService.ShowMessage("Login failed");
}
最重要的是,ViewModel控制了与表示相关的逻辑,但对后面的UI框架一无所知。所有“WPF”代码都在实现IViewService的类中。在您的视图模型中,您“编程到接口”,因此您没有与WPF逻辑紧密耦合,您的ViewModel是“可测试的”,您甚至可以在其他UI平台上重用相同的viewmodel代码。