手写一个WPF-MVVM
- 项目的结构,通常情况下项目会创建Command、Models、Services、ViewModels、Views这几个文件夹。文件夹的作用请看名字。
- MainWindow的代码如下:
1 <Window x:Class="WPF_MVVM.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WPF_MVVM" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="350" Width="525" FontSize="24"> 9 <Grid> 10 <Grid.RowDefinitions> 11 <RowDefinition Height="Auto"/> 12 <RowDefinition Height="*"/> 13 </Grid.RowDefinitions> 14 <Menu> 15 <MenuItem Header="文件"> 16 <MenuItem Header="保存" Command="{Binding SaveCommand}"/> 17 </MenuItem> 18 </Menu> 19 <!--<Button Content="保存"/>--> 20 <Grid Grid.Row="1"> 21 <Grid.RowDefinitions> 22 <RowDefinition Height="Auto"/> 23 <RowDefinition Height="Auto"/> 24 <RowDefinition Height="Auto"/> 25 <RowDefinition Height="*"/> 26 </Grid.RowDefinitions> 27 <TextBox x:Name="tx1" Grid.Row="0" Background="LightBlue" Margin="4" Text="{Binding Path=Input1}"/> 28 <TextBox x:Name="tx2" Grid.Row="1" Background="LightBlue" Margin="4" Text="{Binding Path=Input2}"/> 29 <TextBox x:Name="tx3" Grid.Row="2" Background="LightBlue" Margin="4" Text="{Binding Path=Result}"/> 30 <Button x:Name="addButton" Grid.Row="3" Content="加" Command="{Binding AddCommand}"/> 31 </Grid> 32 </Grid> 33 </Window>
- NotificationObject需要实现接口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 WPF_MVVM.ViewModels 9 { 10 class NotificationObject : INotifyPropertyChanged 11 { 12 public event PropertyChangedEventHandler PropertyChanged; 13 14 public void RaisePropertyChanged(string propertyName) 15 { 16 if (this.PropertyChanged!=null) 17 { 18 this.PropertyChanged.Invoke(this,new PropertyChangedEventArgs(propertyName)); 19 } 20 } 21 } 22 }
- DelegateCommand需要实现接口ICommand。
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 WPF_MVVM.Commands 9 { 10 class DelegateCommand : ICommand 11 { 12 /// <summary> 13 /// 这里定义事件可通知绑定命令的元素IsEnabled是True还是False 14 /// </summary> 15 public event EventHandler CanExecuteChanged 16 { 17 add { CommandManager.RequerySuggested += value; } 18 remove { CommandManager.RequerySuggested -= value; } 19 } 20 21 public bool CanExecute(object parameter) 22 { 23 if (this.CanExecuteFunc==null) 24 { 25 return true; 26 } 27 28 return this.CanExecuteFunc(parameter); 29 } 30 public void Execute(object parameter) 31 { 32 if (this.ExecuteAction == null) 33 { 34 return; 35 } 36 37 this.ExecuteAction(parameter); 38 } 39 public Action<object> ExecuteAction { get; set; } 40 public Func<object,bool> CanExecuteFunc { get; set; } 41 } 42 }
- MainWindowViewModel需要继承于类NotificationObject,通过对属性set的操作中添加this.RaisePropertyChanged("Input1");
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 using Microsoft.Win32; 7 using WPF_MVVM.Commands; 8 9 namespace WPF_MVVM.ViewModels 10 { 11 class MainWindowViewModel:NotificationObject 12 { 13 private double input1; 14 public double Input1 15 { 16 get { return input1;} 17 set 18 { 19 input1 = value; 20 this.RaisePropertyChanged("Input1"); 21 } 22 } 23 24 private double input2; 25 public double Input2 26 { 27 get { return input2; } 28 set 29 { 30 input2 = value; 31 this.RaisePropertyChanged("Input2"); 32 } 33 } 34 35 private double result; 36 public double Result 37 { 38 get { return result; } 39 set 40 { 41 result = value; 42 this.RaisePropertyChanged("Result"); 43 } 44 } 45 public DelegateCommand AddCommand { get; set; } 46 public DelegateCommand SaveCommand { get; set; } 47 private void Add(object parameter) 48 { 49 this.Result = this.Input1 + this.Input2; 50 } 51 52 private bool CanAdd(object parmeter) 53 { 54 if (this.Input1!=0 && this.Input2!=0) 55 { 56 return true; 57 } 58 else 59 { 60 return false; 61 } 62 } 63 64 private void Save(object parameter) 65 { 66 SaveFileDialog saveFileDialog=new SaveFileDialog(); 67 saveFileDialog.ShowDialog(); 68 } 69 public MainWindowViewModel() 70 { 71 this.AddCommand=new DelegateCommand(); 72 this.AddCommand.ExecuteAction=new Action<object>(this.Add); 73 this.AddCommand.CanExecuteFunc=new Func<object, bool>(this.CanAdd); 74 75 this.SaveCommand=new DelegateCommand(); 76 this.SaveCommand.ExecuteAction=new Action<object>(this.Save); 77 } 78 } 79 }
- 如何将MainWindow.xaml与MainWindowViewModel.cs结合呢?
- DataContext,先找当前控件的,然后向上查找对于的DataContext。
- MainWindow.xaml的后台代码实现MainWindow.xaml与MainWindowViewModel.cs结合
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; 7 using System.Windows.Controls; 8 using System.Windows.Data; 9 using System.Windows.Documents; 10 using System.Windows.Input; 11 using System.Windows.Media; 12 using System.Windows.Media.Imaging; 13 using System.Windows.Navigation; 14 using System.Windows.Shapes; 15 using WPF_MVVM.ViewModels; 16 17 namespace WPF_MVVM 18 { 19 /// <summary> 20 /// 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 }
转载于:https://www.cnblogs.com/bjxingch/articles/9669905.html