一、构建ViewModels
设计模式的其中一个目标就是抽象构造一个给出指定类型的对象或者实现指定类型的接口的过程。需要把类给客户端,让客户端去使用,但是要隐藏类是具体的实现细节。
1.1The Application
在View中有个一个App,实现Application这个文件可以用来管理ViewModels。
xaml:
<Application x:Class="MvvmWpfApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:viewModel="clrnamespace:
MvvmWpfApp.ViewModel;assembly=MvvmWpfApp.ViewModel"
Startup="Application_Startup">
<Application.Resources>
<viewModel:ApplicationViewModel x:Key="applicationViewModel" />
</Application.Resources>
</Application>
cs:
public partial class App : Application
{
private ApplicationViewModel _appViewModel;
private void Application_Startup(object sender, StartupEventArgs e)
{
_appViewModel = Resources["applicationViewModel"] as ApplicationViewModel;
if(_appViewModel != null)
{
_appViewModel.Startup();
}
}
}
1.2The Main Window
namespace MvvmWpfApp { //通过ApplicationViewModel来获取一个MainViewModel //从而赋给MainWindow.DataContext; public partial class App :Application { ApplicationViewModel _appViewModel; private void Application_Startup(object sender, StartupEventArgs e) { _appViewModel = Resources["applicationViewModel"] as ApplicationViewModel; if (_appViewModel != null) { _appViewModel.Startup(); MainViewModel mainViewModel = _appViewModel.CreateMainViewModel(); MainWindow mainWindow = new MainWindow(); mainWindow.DataContext = mainViewModel; this.MainWindow = mainWindow; this.MainWindow.Show(); } } } }
1.3并发处理
dispatchobject把system.object实例绑定到dispatcher上,意味着只有dispatcher创造的线程可以访问这个对象。wpf通常有两个线程,一个用于呈 现,一个用于处理UI和程序的代码。后者不止一个职责,在点击按钮事件代码里面System.Threading.Thread.Sleep(10000),如果在移动UI,那么UI是不会动的。因为线程处于休眠状态了。处理UI移动的线程和程序代码用的是同一个线程。通常如果model或者是ViewModel接受到的不是UI线程的事件,会出现InvalidOperationExpcetion.
二、避免在viewmodel中出现调用view中的类。
当使用mvvm时,可能会有种情况是,当一个点击菜单按钮,要弹出另一个窗体,此时最好不要去直接new一个窗体而破坏mvvm的模式,可以使用接口:
public interface IFilePathProvider { string GetLoadPath(); string GetSavePath(); } public MainWindowViewModel(IFilePathProvider filePathFinder) { _filePathFinder = filePathFinder; } private void Load() { string loadFilePath = _filePathFinder.GetLoadPath(); if (loadFilePath != null) { // The user has selected a file to open } } private void Save() { string saveFilePath = _filePathFinder.GetSavePath(); if(saveFilePath != null) { // The user has selected a file to save } } public class FilePathProvider : IFilePathProvider { public string GetLoadPath() { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "XML files (*.xml)|*.xml"; string filePath = null; bool? dialogResult = ofd.ShowDialog(); if(dialogResult.HasValue && dialogResult.Value) { filePath = ofd.FileName; } return filePath; } public string GetSavePath() { SaveFileDialog sfd = new SaveFileDialog(); sfd.Filter = "XML files (*.xml)|*.xml"; string filePath = null; bool? dialogResult = sfd.ShowDialog(); if (dialogResult.HasValue && dialogResult.Value) { filePath = sfd.FileName; } return filePath; } }