初识MVVM
2017-09-22 10:34
134 查看
MVVM分解:
M-> 源数据一堆get,set方法,对应Java中,JavaBean
V-> 窗体,显示界面
VM-> 业务逻辑层,对窗体的逻辑响应,及数据传输的处理。
这样做的优点:
窗体改变,只需变动窗体样式,绑定对应的数据及响应事件(VM)。
VM只需处理逻辑改变
M只需添加数据或删除数据,及将数据变化反馈给UI
MVVM需要实现两个关键接口。
A)
ICommand接口,此接口用于实现界面响应事件的委托
B)
INotifyPropertyChanged接口,此接口用于实现 界面和数据源同步变化
以登录窗体为例,实现
A)修改Module中数据,改变界面显示
B)修改界面输入数据,同步Module中的数据
1)新建工程,KnowXAML
主界面类.cs如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using KnowXAML.ModuleView;
namespace
KnowXAML
{
///<summary>
/// Interaction logic for MainWindow.xaml
///</summary>
public partial
class MainWindow :
Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
2)新建ICommand界面命令代理类
UICommand. UICommand用于实现空间响应事件的代理。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace
KnowXAML.DelegateCommand
{
class
UICommand :
ICommand
{
///<summary>
///判断控件是否可用
///</summary>
Func<object,
bool> canExecute;
///<summary>
///执行方法
///</summary>
Action<object>
executeAction;
bool canExecuteCache;
public event
EventHandler CanExecuteChanged;
public UICommand(Action<object>
executeAction, Func<object,
bool> canExecute)
{
this.executeAction = executeAction;
this.canExecute = canExecute;
}
bool
ICommand.CanExecute(objectparameter)
{
bool temp = canExecute(parameter);
if (canExecuteCache != temp)
{
canExecuteCache = temp;
if
(CanExecuteChanged != null)
CanExecuteChanged(this,
newEventArgs());
}
return canExecuteCache;
}
void ICommand.Execute(object
parameter)
{
executeAction(parameter);
}
}
}
3)创建类UINotifier,实现界面数据同步接口INotifyPropertyChanged。此类用于同步界面和底层类(Bean)数据。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
namespace
KnowXAML.DelegateNotifer
{
public abstract
class UINotifier :
INotifyPropertyChanged
{
#region INotifyPropertyChanged
publiceventPropertyChangedEventHandler
PropertyChanged;
#endregion
#region Protected
protectedvirtualvoid
OnPropertyChanged(stringpropertyName)
{
if (PropertyChanged !=
null)
PropertyChanged(this,
newPropertyChangedEventArgs(propertyName));
}
#endregion
}
}
4)创建底层数据类(Bean),User,继承类DelegateNotifer
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Threading.Tasks;
using KnowXAML.DelegateNotifer;
namespace
KnowXAML.Module
{
public
class
User :
UINotifier
{
private
string userName;
public
string Name
{
get
{
return
userName;
}
set
{
userName =
value;
OnPropertyChanged("Name");
}
}
private
string userPassword;
public string
Password
{
get
{
return
userPassword;
}
set
{
userPassword =
value;
OnPropertyChanged("Password");
}
}
}
}
5)创建ModuleView类,用于User类和界面的数据桥接。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using KnowXAML.Module;
using KnowXAML.DelegateCommand;
using KnowXAML.DelegateNotifer;
namespace
KnowXAML.ModuleView
{
class
UserModuleView
{
public
User user {
get;
set; }
public UICommand
uiCommand { get;
set; }
public UserModuleView()
{
this.user =
newUser();
this.uiCommand =
new UICommand(SetUserInfo,
arg=>true); //指定命令外//部接口uiCommand对应函数为SetUserInfo。uiCommand用于XMAL中配置
}
public void
SetUserInfo(object parm)
{
user.Name =
"zhangsan";
user.Password =
"123124";
}
public User
userMode
{
get
{
return
user;
}
set
{
if
(user == value)
return;
user =
value;
}
}
}
}
6)添加控件,修改XMAL,添加数据绑定及响应事件。黄色背景处为添加数据源,及响应事件项。
XMAL格式如下:
<Window
x:Class="KnowXAML.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:KnowXAML"
xmlns:vm="clr-namespace:KnowXAML.ModuleView"
mc:Ignorable="d"
Title="MainWindow"Height="277.407"
Width="525">
<Window.DataContext>
<vm:UserModuleView
/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="118*"/>
<ColumnDefinition
Width="401*"/>
</Grid.ColumnDefinitions>
<GroupBox
x:Name="groupBox"Header="GroupBox"
HorizontalAlignment="Left"Margin="10,26,0,-0.4"VerticalAlignment="Top"
Height="224"Width="498"
Background="AliceBlue"Grid.ColumnSpan="2">
<Grid
HorizontalAlignment="Left"Margin="10,10,-3.2,34.4"
Width="478">
<Grid.ColumnDefinitions>
<ColumnDefinitionWidth="115*"/>
<ColumnDefinitionWidth="363*"/>
</Grid.ColumnDefinitions>
<Label
x:Name="lblUserName"Content="UserName:"HorizontalAlignment="Left"
Margin="31,24,0,0"VerticalAlignment="Top"
Width="86"FontSize="16"
Grid.ColumnSpan="2"/>
<TextBox
x:Name="txtUserName"HorizontalAlignment="Left"
Height="27" Margin="20.587,29,0,0"
Text="{Binding
Path= userMode.Name}"TextWrapping="Wrap" VerticalAlignment="Top"Width="251"
FontSize="16"Grid.Column="1"/>
<Label
x:Name="lblPassword"Content="Password:"
FontSize="16" HorizontalAlignment="Left"Margin="36,82,0,0"VerticalAlignment="Top"RenderTransformOrigin="-0.205,0.338"Grid.ColumnSpan="2"/>
<TextBox
x:Name="txtPassword"HorizontalAlignment="Left" FontSize="16"Text="{Binding
Path= userMode.Password}" Height="25"Margin="20.587,88,0,0"TextWrapping="Wrap" VerticalAlignment="Top"Width="251"
Grid.Column="1"/>
<Button
x:Name="btnCancel"Content="Cancel"HorizontalAlignment="Left"
Margin="62.587,132,0,0"VerticalAlignment="Top"
Width="75"Grid.Column="1"/>
<Button
x:Name="btnOK" Command="{Binding
uiCommand}" Content="OK"HorizontalAlignment="Left"
Margin="196.587,132,0,0"VerticalAlignment="Top"
Width="75"Grid.Column="1"/>
</Grid>
</GroupBox>
</Grid>
</Window>
7)运行界面
初始化界面:
点击“OK”后界面
修改UserName后,点击“OK”
如果觉得我写的还不错,请关注我的微信:
M-> 源数据一堆get,set方法,对应Java中,JavaBean
V-> 窗体,显示界面
VM-> 业务逻辑层,对窗体的逻辑响应,及数据传输的处理。
这样做的优点:
窗体改变,只需变动窗体样式,绑定对应的数据及响应事件(VM)。
VM只需处理逻辑改变
M只需添加数据或删除数据,及将数据变化反馈给UI
MVVM需要实现两个关键接口。
A)
ICommand接口,此接口用于实现界面响应事件的委托
B)
INotifyPropertyChanged接口,此接口用于实现 界面和数据源同步变化
以登录窗体为例,实现
A)修改Module中数据,改变界面显示
B)修改界面输入数据,同步Module中的数据
1)新建工程,KnowXAML
主界面类.cs如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using KnowXAML.ModuleView;
namespace
KnowXAML
{
///<summary>
/// Interaction logic for MainWindow.xaml
///</summary>
public partial
class MainWindow :
Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
2)新建ICommand界面命令代理类
UICommand. UICommand用于实现空间响应事件的代理。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
namespace
KnowXAML.DelegateCommand
{
class
UICommand :
ICommand
{
///<summary>
///判断控件是否可用
///</summary>
Func<object,
bool> canExecute;
///<summary>
///执行方法
///</summary>
Action<object>
executeAction;
bool canExecuteCache;
public event
EventHandler CanExecuteChanged;
public UICommand(Action<object>
executeAction, Func<object,
bool> canExecute)
{
this.executeAction = executeAction;
this.canExecute = canExecute;
}
bool
ICommand.CanExecute(objectparameter)
{
bool temp = canExecute(parameter);
if (canExecuteCache != temp)
{
canExecuteCache = temp;
if
(CanExecuteChanged != null)
CanExecuteChanged(this,
newEventArgs());
}
return canExecuteCache;
}
void ICommand.Execute(object
parameter)
{
executeAction(parameter);
}
}
}
3)创建类UINotifier,实现界面数据同步接口INotifyPropertyChanged。此类用于同步界面和底层类(Bean)数据。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
namespace
KnowXAML.DelegateNotifer
{
public abstract
class UINotifier :
INotifyPropertyChanged
{
#region INotifyPropertyChanged
publiceventPropertyChangedEventHandler
PropertyChanged;
#endregion
#region Protected
protectedvirtualvoid
OnPropertyChanged(stringpropertyName)
{
if (PropertyChanged !=
null)
PropertyChanged(this,
newPropertyChangedEventArgs(propertyName));
}
#endregion
}
}
4)创建底层数据类(Bean),User,继承类DelegateNotifer
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Threading.Tasks;
using KnowXAML.DelegateNotifer;
namespace
KnowXAML.Module
{
public
class
User :
UINotifier
{
private
string userName;
public
string Name
{
get
{
return
userName;
}
set
{
userName =
value;
OnPropertyChanged("Name");
}
}
private
string userPassword;
public string
Password
{
get
{
return
userPassword;
}
set
{
userPassword =
value;
OnPropertyChanged("Password");
}
}
}
}
5)创建ModuleView类,用于User类和界面的数据桥接。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using KnowXAML.Module;
using KnowXAML.DelegateCommand;
using KnowXAML.DelegateNotifer;
namespace
KnowXAML.ModuleView
{
class
UserModuleView
{
public
User user {
get;
set; }
public UICommand
uiCommand { get;
set; }
public UserModuleView()
{
this.user =
newUser();
this.uiCommand =
new UICommand(SetUserInfo,
arg=>true); //指定命令外//部接口uiCommand对应函数为SetUserInfo。uiCommand用于XMAL中配置
}
public void
SetUserInfo(object parm)
{
user.Name =
"zhangsan";
user.Password =
"123124";
}
public User
userMode
{
get
{
return
user;
}
set
{
if
(user == value)
return;
user =
value;
}
}
}
}
6)添加控件,修改XMAL,添加数据绑定及响应事件。黄色背景处为添加数据源,及响应事件项。
XMAL格式如下:
<Window
x:Class="KnowXAML.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:KnowXAML"
xmlns:vm="clr-namespace:KnowXAML.ModuleView"
mc:Ignorable="d"
Title="MainWindow"Height="277.407"
Width="525">
<Window.DataContext>
<vm:UserModuleView
/>
</Window.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="118*"/>
<ColumnDefinition
Width="401*"/>
</Grid.ColumnDefinitions>
<GroupBox
x:Name="groupBox"Header="GroupBox"
HorizontalAlignment="Left"Margin="10,26,0,-0.4"VerticalAlignment="Top"
Height="224"Width="498"
Background="AliceBlue"Grid.ColumnSpan="2">
<Grid
HorizontalAlignment="Left"Margin="10,10,-3.2,34.4"
Width="478">
<Grid.ColumnDefinitions>
<ColumnDefinitionWidth="115*"/>
<ColumnDefinitionWidth="363*"/>
</Grid.ColumnDefinitions>
<Label
x:Name="lblUserName"Content="UserName:"HorizontalAlignment="Left"
Margin="31,24,0,0"VerticalAlignment="Top"
Width="86"FontSize="16"
Grid.ColumnSpan="2"/>
<TextBox
x:Name="txtUserName"HorizontalAlignment="Left"
Height="27" Margin="20.587,29,0,0"
Text="{Binding
Path= userMode.Name}"TextWrapping="Wrap" VerticalAlignment="Top"Width="251"
FontSize="16"Grid.Column="1"/>
<Label
x:Name="lblPassword"Content="Password:"
FontSize="16" HorizontalAlignment="Left"Margin="36,82,0,0"VerticalAlignment="Top"RenderTransformOrigin="-0.205,0.338"Grid.ColumnSpan="2"/>
<TextBox
x:Name="txtPassword"HorizontalAlignment="Left" FontSize="16"Text="{Binding
Path= userMode.Password}" Height="25"Margin="20.587,88,0,0"TextWrapping="Wrap" VerticalAlignment="Top"Width="251"
Grid.Column="1"/>
<Button
x:Name="btnCancel"Content="Cancel"HorizontalAlignment="Left"
Margin="62.587,132,0,0"VerticalAlignment="Top"
Width="75"Grid.Column="1"/>
<Button
x:Name="btnOK" Command="{Binding
uiCommand}" Content="OK"HorizontalAlignment="Left"
Margin="196.587,132,0,0"VerticalAlignment="Top"
Width="75"Grid.Column="1"/>
</Grid>
</GroupBox>
</Grid>
</Window>
7)运行界面
初始化界面:
点击“OK”后界面
修改UserName后,点击“OK”
如果觉得我写的还不错,请关注我的微信:
相关文章推荐
- 【MVVM Light】新手初识MVVM,你一看就会
- 初识 WPF/Silverlight MVVM模式
- WPF——初识MVVM(二)
- 初识MVVM
- 初识MVVM的心得
- Vue.js-----轻量高效的MVVM框架(一、初识Vue.js)
- 【MVVM Light】新手初识MVVM,你一看就会
- 20161119微信小程序初识
- boost之初识thread
- hadoop学习笔记之初识
- 初识BeeFrameWork
- 10min初识观察者模式
- MVVM项目实战之路-搭建一个登录界面
- java中的内部类初识
- 5-1图层初识
- 初识Android延时(postDelayed和schedule)
- JAVA初识之数据类型 运算符 流程控制
- Poechant 解读 Java API —— 借助货币格式化,初识 Locale 和 NumberFormat
- 初识NuGet - 概念, 安装和使用
- AngularJS 001:初识