首页 > 代码库 > 利刃 MVVMLight 3:双向数据绑定

利刃 MVVMLight 3:双向数据绑定

      上篇我们已经了解了MVVM的框架结构和运行原理。这里我们来看一下伟大的双向数据绑定。
说到双向绑定,大家比较熟悉的应该就是AngularJS了,几乎所有的AngularJS 系列教程的开篇几章都要涉及到,真的是很好用。
表达的效果很简单:就是在界面的操作对数据模型的修改能实时反映到数据;而数据的变更能实时展现到界面。即视图数据模型(ViewModel)和视图(View)之间的双向绑定和触发。
 
技术分享
 
 
我们来操作一个试试看:
第一步:先写一个Model,里面包含我们需要的数据信息,代码如下:
 1     /// <summary> 2     /// 用户信息 3     /// </summary> 4     public class UserInfoModel : ObservableObject 5     { 6         private String userName; 7         /// <summary> 8         /// 用户名称 9         /// </summary>10         public String UserName11         {12             get { return userName; }13             set { userName = value; RaisePropertyChanged(()=>UserName); }14         }15 16         private Int64 userPhone;17         /// <summary>18         /// 用户电话19         /// </summary>20         public Int64 UserPhone21         {22             get { return userPhone; }23             set { userPhone = value; RaisePropertyChanged(() => UserPhone); }24         }25 26         private Int32 userSex;27         /// <summary>28         /// 用户性别29         /// </summary>30         public Int32 UserSex31         {32             get { return userSex; }33             set { userSex = value; RaisePropertyChanged(()=>UserSex); }34         }35 36         private String userAdd;37         /// <summary>38         /// 用户地址39         /// </summary>40         public String UserAdd41         {42             get { return userAdd; }43             set { userAdd = value; RaisePropertyChanged(() => UserAdd); }44         }45     }

 

第二步:写一个ViewModel,包含了View所需要的命令和属性:
 1     public class BothWayBindViewModel:ViewModelBase 2     { 3         public BothWayBindViewModel() 4         { 5             UserInfo = new UserInfoModel(); 6         } 7          8         #region 属性 9 10         private UserInfoModel userInfo;11         /// <summary>12         /// 用户信息13         /// </summary>14         public UserInfoModel UserInfo15         {16             get { return userInfo; }17             set { userInfo = value; RaisePropertyChanged(() => UserInfo); }18         }19 20         #endregion21         22         #region 命令23         #endregion24     }

 

第三步:在ViewModelLocator中注册我们写好的ViewModel:SimpleIoc.Default.Register<BothWayBindViewModel>();
 1 /* 2   In App.xaml: 3   <Application.Resources> 4       <vm:ViewModelLocator xmlns:vm="clr-namespace:MVVMLightDemo" 5                            x:Key="Locator" /> 6   </Application.Resources> 7    8   In the View: 9   DataContext="{Binding Source={StaticResource Locator}, Path=ViewModelName}"10 11   You can also use Blend to do all this with the tool‘s support.12   See http://www.galasoft.ch/mvvm13 */14 15 using GalaSoft.MvvmLight;16 using GalaSoft.MvvmLight.Ioc;17 using Microsoft.Practices.ServiceLocation;18 19 namespace MVVMLightDemo.ViewModel20 {21     /// <summary>22     /// This class contains static references to all the view models in the23     /// application and provides an entry point for the bindings.24     /// </summary>25     public class ViewModelLocator26     {27         /// <summary>28         /// Initializes a new instance of the ViewModelLocator class.29         /// </summary>30         public ViewModelLocator()31         {32             ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);33 34             #region Code Example35             ////if (ViewModelBase.IsInDesignModeStatic)36             ////{37             ////    // Create design time view services and models38             ////    SimpleIoc.Default.Register<IDataService, DesignDataService>();39             ////}40             ////else41             ////{42             ////    // Create run time view services and models43             ////    SimpleIoc.Default.Register<IDataService, DataService>();44             ////}45             #endregion46 47             SimpleIoc.Default.Register<MainViewModel>();48             SimpleIoc.Default.Register<WelcomeViewModel>();49             SimpleIoc.Default.Register<BothWayBindViewModel>();    50         }51 52         #region 实例化53         public MainViewModel Main54         {55             get56             {57                 return ServiceLocator.Current.GetInstance<MainViewModel>();58             }59         }60 61         public WelcomeViewModel Welcome62         {63             get64             { 65                return ServiceLocator.Current.GetInstance<WelcomeViewModel>();66             }67         }68 69         public BothWayBindViewModel BothWayBind70         {71             get72             { 73                 return ServiceLocator.Current.GetInstance<BothWayBindViewModel>();74             }75         }     76 77         #endregion78 79         public static void Cleanup()80         {81             // TODO Clear the ViewModels82         }83     }84 }

 

第四步:编写View(注意标红的代码):
 
 1 <Window x:Class="MVVMLightDemo.View.BothWayBindView" 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4          DataContext="{Binding Source={StaticResource Locator},Path=BothWayBind}" 5         Title="BothWayBindView" Height="300" Width="300"> 6     <Grid> 7             <StackPanel Orientation="Vertical" Margin="10,10,0,0"> 8                 <StackPanel Orientation="Horizontal" > 9                     <TextBlock Text="请输入姓名:" ></TextBlock>10                     <TextBox Text="{Binding UserInfo.UserName,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Width="200" ></TextBox>11                 </StackPanel>12 13                 <StackPanel Margin="0,10,0,0" Orientation="Horizontal" >14                     <TextBlock Text="Hello " ></TextBlock>15                     <TextBlock Text="{Binding UserInfo.UserName}" ></TextBlock>16                 </StackPanel>17 18                 <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal" >19                 </StackPanel>20                 21             </StackPanel>22     </Grid>23 </Window>

效果如图所示(当修改输入框的内容的时候,对应绑定数据相应改变,并触发对UI的修改,所以下面那行文字也相应改变改变。):

技术分享
 
前面我们已经了解到了,RaisePropertyChanged的作用是当数据源改变的时候,会触发PropertyChanged事件达到通知UI更改的目的(ViewModel => View)。
 
那View上的变化要怎么通知到数据源呢:
View中文本框绑定内容如下:{Binding UserInfo.UserName,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay},
大家会看到多了两个属性,一个是UpdateSourceTrigger,一个是Mode属性。
UpdateSourceTrigger的作用是 当做何种改变的时候通知数据源我们做了改变。
 
 
枚举类型效果
Default默认值(默认为LostFocuse)
Explicit当应用程序调用 UpdateSource 方法时生效
LostFocus失去焦点的时候触发
PropertyChanged数据属性改变的时候触发
 
这边我们直接使用 PropertyChanged,当UI数据改变的时候,我们再通知到数据源去做修改。
 
 
还有一个属性就是Mode,他有五个参数:
枚举类型效果
OneWay源发生变化,数据就会从源流向目标
OneTime绑定会将数据从源发送到目标;但是,仅当启动了应用程序或 DataContext 发生更改时才会如此操作,因此,它不会侦听源中的更改通知。
OneWayToSource绑定会将数据从目标发送到源
TwoWay绑定会将源数据发送到目标,但如果目标属性的值发生变化,则会将它们发回给源
Default绑定的模式根据实际情况来定,如果是可编辑的就是TwoWay,只读的就是OneWay
 
 
这边明显有很多种选择,明确一点的是,我们是想把View上的变化同步到ViewModel(Target => Source),所以使用OneWayToSource、TwoWay、Default或者不写都可以。
严谨点应该使用OneWayToSource。因为是文本框,属于可以编辑控件,所以 Default指向的是TwoWay。
下面还有一个TextBlock,仅仅用于显示的,所以不需要目标对源的修改,无需指定就默认是OneWay,当源改变的时候,会通知它进行修改。
 
点击下载代码
 
转载请标明出处,谢谢
 

利刃 MVVMLight 3:双向数据绑定