WPF简单MVVM实现
1. MVVM介绍:
MVVM就是: Model -- 模型(现实中对象的抽象)
View -- UI(用户界面)
ViewModel -- UI界面的抽象(给View提供数据,并响应View的操作)
2. 关键是要能准确的进行ViewModel的建模,处理好View与ViewModel之间的关系
2.1. 只有2种关系:
数据传递 --- 双向,使用Binding实现;
操作传递 --- 单向(只从View传递给ViewModel),使用命令Command实现;
3. 开始
3.1. 首先创建NotificationObject,它是所以ViewModel的基类
因为要使用Binding,而ViewModel就充当数据源的角色,而要实现当值有变化时会自动响应,就必须实现INotifyPropertyChanged接口,代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace MVVMTest.ViewModels 9 { 10 public class NotificationObject:INotifyPropertyChanged 11 { 12 public event PropertyChangedEventHandler PropertyChanged; 13 14 public void RaisePropertyChanged(string property) 15 { 16 if (this.PropertyChanged != null) 17 this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(property)); 18 19 } 20 } 21 }
3.2.接着要创建DelegateCommand,实现了ICommand接口,用来处理View发送到ViewModel的命令,代码如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using System.Windows.Input; 7 8 namespace MVVMTest.Commands 9 { 10 public class DelegateCommand:ICommand 11 { 12 public bool CanExecute(object parameter) 13 { 14 if (this.CanExecuteFunc == null) 15 { 16 return true; 17 } 18 19 return this.CanExecuteFunc(parameter); 20 } 21 22 public event EventHandler CanExecuteChanged; 23 24 public void Execute(object parameter) 25 { 26 if (this.ExecuteAction == null) 27 { 28 return; 29 } 30 this.ExecuteAction(parameter); 31 } 32 33 public Action<object> ExecuteAction { get; set; } 34 public Func<object, bool> CanExecuteFunc { get; set; } 35 } 36 }
3.3.为了方便开发,这里推荐自定义一个code snippet(代码块):
放到此目录下C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC#\Snippets\1033\Visual C#
1 <?xml version="1.0" encoding="utf-8" ?> 2 <CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> 3 <CodeSnippet Format="1.0.0"> 4 <Header> 5 <Title>propn</Title> 6 <Shortcut>propn</Shortcut> 7 <Description>Code snippet for NotificationObject property and backing field</Description> 8 <Author>Microsoft Corporation</Author> 9 <SnippetTypes> 10 <SnippetType>Expansion</SnippetType> 11 </SnippetTypes> 12 </Header> 13 <Snippet> 14 <Declarations> 15 <Literal> 16 <ID>type</ID> 17 <ToolTip>Property type</ToolTip> 18 <Default>int</Default> 19 </Literal> 20 <Literal> 21 <ID>property</ID> 22 <ToolTip>Property name</ToolTip> 23 <Default>MyProperty</Default> 24 </Literal> 25 <Literal> 26 <ID>field</ID> 27 <ToolTip>The variable backing this property</ToolTip> 28 <Default>myVar</Default> 29 </Literal> 30 </Declarations> 31 <Code Language="csharp"><![CDATA[private $type$ $field$; 32 33 public $type$ $property$ 34 { 35 get { return $field$;} 36 set { 37 $field$ = value; 38 this.RaisePropertyChanged("$property$"); 39 } 40 } 41 $end$]]> 42 </Code> 43 </Snippet> 44 </CodeSnippet> 45 </CodeSnippets>
3.4. 由于这个例子较简单,所以没有设计到Model的设计,而直接到ViewModel的设计,一般的规则是每个View就有一个对应的ViewModel,而ViewModel是充当View的数据源的,所以只需要考虑View需要什么数据、含有哪些操作,创建MainWindow的ViewModel,MainWindowViewModel,代码如下:
1 using MVVMTest.Commands; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace MVVMTest.ViewModels 9 { 10 public class MainWindowViewModel:NotificationObject 11 { 12 private string txt1; 13 14 public string Txt1 15 { 16 get { return txt1; } 17 set 18 { 19 txt1 = value; 20 this.RaisePropertyChanged("Txt1"); 21 } 22 } 23 24 private string txt2; 25 26 public string Txt2 27 { 28 get { return txt2; } 29 set 30 { 31 txt2 = value; 32 this.RaisePropertyChanged("Txt2"); 33 } 34 } 35 36 private string result; 37 38 public string Result 39 { 40 get { return result; } 41 set 42 { 43 result = value; 44 this.RaisePropertyChanged("Result"); 45 } 46 } 47 48 public DelegateCommand ConcatCommand { get; set; } 49 public void Concat(object parameter) 50 { 51 Result = Txt1 + " and " + Txt2; 52 } 53 54 55 public MainWindowViewModel() 56 { 57 ConcatCommand = new DelegateCommand(); 58 ConcatCommand.ExecuteAction = new Action<object>(Concat); 59 } 60 61 62 63 } 64 }
3.4.将ViewModel作为数据源赋值给View的DataContext
1 using MVVMTest.ViewModels; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 using System.Windows; 8 using System.Windows.Controls; 9 using System.Windows.Data; 10 using System.Windows.Documents; 11 using System.Windows.Input; 12 using System.Windows.Media; 13 using System.Windows.Media.Imaging; 14 using System.Windows.Navigation; 15 using System.Windows.Shapes; 16 17 namespace MVVMTest 18 { 19 /// <summary> 20 /// Interaction logic for MainWindow.xaml 21 /// </summary> 22 public partial class MainWindow : Window 23 { 24 public MainWindow() 25 { 26 InitializeComponent(); 27 this.DataContext = new MainWindowViewModel(); 28 } 29 } 30 }
3.5.在View中绑定数据:
1 <Window x:Class="MVVMTest.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 Title="MainWindow" Height="350" Width="525"> 5 <Grid> 6 <TextBox Margin="40,51,311,216" Text="{Binding Txt1}"/> 7 <TextBox Margin="230,51,114,216" Text="{Binding Txt2}"/> 8 <TextBox Margin="128,152,176,139" Text="{Binding Result}"/> 9 <Button Margin="313,241,64,23" Command="{Binding ConcatCommand}"/> 10 </Grid> 11 </Window>
源代码:http://yunpan.cn/c3c7AAXm4U2dP 访问密码 8788