首先MVVM设计模式的结构,
Views: 由Window/Page/UserControl等构成,通过DataBinding与ViewModels建立关联;
ViewModels:由一组命令,可以绑定的属性,操作逻辑构成;因为View与ViewModel进行了解耦,我们可以对ViewModel进行Unit Test;
Models:可以是实体对象或者Web服务;
下面通过一个简单的例子,来介绍一些WPF MVVM模式。示例将展示一个图片浏览器,打开图片,放大/缩小图片大小。首先项目结构:
UI:
<Grid> <DockPanel> <Menu DockPanel.Dock="Top"> <Menu> <MenuItem Header="_Open" Command="{Binding OpenFileCommand}"/> </Menu> <Menu> <MenuItem Header="_ZoomIn" Command="{Binding ZoomCommand}" CommandParameter="ZoomIn"/> </Menu> <Menu> <MenuItem Header="_ZoomOut" Command="{Binding ZoomCommand}" CommandParameter="ZoomOut"/> </Menu> <Menu> <MenuItem Header="_Normal" Command="{Binding ZoomCommand}" CommandParameter="Normal"/> </Menu> </Menu> <ScrollViewer> <Image Source="{Binding ImagePath}" Stretch="None"> <Image.LayoutTransform> <ScaleTransform ScaleX="{Binding Zoom}" ScaleY="{Binding Zoom}"/> </Image.LayoutTransform> </Image> </ScrollViewer> </DockPanel> </Grid>
ViewModelBase(用来实现修改通知):
public class ViewModelBase : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propName) { if(PropertyChanged!=null) { PropertyChanged(this, new PropertyChangedEventArgs(propName)); } } }
OpenFileCommand:
public class OpenFileCommand : ICommand { private MainViewModel _data; public OpenFileCommand(MainViewModel data) { _data = data; } public event EventHandler CanExecuteChanged; public bool CanExecute(object parameter) { return true; } public void Execute(object parameter) { OpenFileDialog dialog = new OpenFileDialog() { Filter = "Image Files|*.jpg;*.png;*.bmp;*.gif" }; if(dialog.ShowDialog().GetValueOrDefault()) { _data.ImagePath = dialog.FileName; } }
ZoomCommand:
public enum ZoomType { ZoomIn = 0, ZoomOut = 1, Normal = 2 } public class ZoomCommand : ICommand { private MainViewModel _data; public ZoomCommand(MainViewModel data) { _data = data; } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } public bool CanExecute(object parameter) { return _data.ImagePath != null; } public void Execute(object parameter) { ZoomType type = (ZoomType)Enum.Parse(typeof(ZoomType), (string)parameter, true); switch(type) { case ZoomType.Normal: _data.Zoom = 1; break; case ZoomType.ZoomIn: _data.Zoom *= 1.2; break; case ZoomType.ZoomOut: _data.Zoom /= 1.2; break; } } }
MainViewModel:
public class MainViewModel : ViewModelBase { private string _imagePath; public string ImagePath { get { return _imagePath; } set { if (_imagePath != value) { _imagePath = value; OnPropertyChanged("ImagePath"); } } } private double _zoom = 1.0; public double Zoom { get { return _zoom; } set { if(_zoom != value) { _zoom = value; OnPropertyChanged("Zoom"); } } } private ICommand _openFileCommand; public ICommand OpenFileCommand { get { return _openFileCommand; } } private ZoomCommand _zoomCommand; public ZoomCommand ZoomCommand { get { return _zoomCommand; } } public MainViewModel() { _openFileCommand = new OpenFileCommand(this); _zoomCommand = new ZoomCommand(this); } }
下一步我们要做的是将MainViewModel绑定到MainWindow上,我们可以通过下面两种方式绑定:
1. 直接在MainWindow的Code Behind中进行绑定:
public MainWindow() { InitializeComponent(); DataContext = new MainViewModel(); }
2. 在App.xaml后台代码中绑定(将App.xaml中StartupUri="MainWindow.xaml"删除掉):
public App() { MainWindow window = new MainWindow(); window.DataContext = new MainViewModel(); window.Show(); }
程序运行效果如下:
到此为止,这个简单的示例就算完成了。点击这里下载代码。
感谢您的阅读。
时间: 2024-12-21 19:26:04