• 利刃 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 UserName
    11         {
    12             get { return userName; }
    13             set { userName = value; RaisePropertyChanged(()=>UserName); }
    14         }
    15 
    16         private Int64 userPhone;
    17         /// <summary>
    18         /// 用户电话
    19         /// </summary>
    20         public Int64 UserPhone
    21         {
    22             get { return userPhone; }
    23             set { userPhone = value; RaisePropertyChanged(() => UserPhone); }
    24         }
    25 
    26         private Int32 userSex;
    27         /// <summary>
    28         /// 用户性别
    29         /// </summary>
    30         public Int32 UserSex
    31         {
    32             get { return userSex; }
    33             set { userSex = value; RaisePropertyChanged(()=>UserSex); }
    34         }
    35 
    36         private String userAdd;
    37         /// <summary>
    38         /// 用户地址
    39         /// </summary>
    40         public String UserAdd
    41         {
    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 UserInfo
    15         {
    16             get { return userInfo; }
    17             set { userInfo = value; RaisePropertyChanged(() => UserInfo); }
    18         }
    19 
    20         #endregion
    21         
    22         #region 命令
    23         #endregion
    24     }
    复制代码
    第三步:在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/mvvm
    13 */
    14 
    15 using GalaSoft.MvvmLight;
    16 using GalaSoft.MvvmLight.Ioc;
    17 using Microsoft.Practices.ServiceLocation;
    18 
    19 namespace MVVMLightDemo.ViewModel
    20 {
    21     /// <summary>
    22     /// This class contains static references to all the view models in the
    23     /// application and provides an entry point for the bindings.
    24     /// </summary>
    25     public class ViewModelLocator
    26     {
    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 Example
    35             ////if (ViewModelBase.IsInDesignModeStatic)
    36             ////{
    37             ////    // Create design time view services and models
    38             ////    SimpleIoc.Default.Register<IDataService, DesignDataService>();
    39             ////}
    40             ////else
    41             ////{
    42             ////    // Create run time view services and models
    43             ////    SimpleIoc.Default.Register<IDataService, DataService>();
    44             ////}
    45             #endregion
    46 
    47             SimpleIoc.Default.Register<MainViewModel>();
    48             SimpleIoc.Default.Register<WelcomeViewModel>();
    49             SimpleIoc.Default.Register<BothWayBindViewModel>();    
    50         }
    51 
    52         #region 实例化
    53         public MainViewModel Main
    54         {
    55             get
    56             {
    57                 return ServiceLocator.Current.GetInstance<MainViewModel>();
    58             }
    59         }
    60 
    61         public WelcomeViewModel Welcome
    62         {
    63             get
    64             { 
    65                return ServiceLocator.Current.GetInstance<WelcomeViewModel>();
    66             }
    67         }
    68 
    69         public BothWayBindViewModel BothWayBind
    70         {
    71             get
    72             { 
    73                 return ServiceLocator.Current.GetInstance<BothWayBindViewModel>();
    74             }
    75         }     
    76 
    77         #endregion
    78 
    79         public static void Cleanup()
    80         {
    81             // TODO Clear the ViewModels
    82         }
    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,当源改变的时候,会通知它进行修改。
     
  • 相关阅读:
    超强web页面上绘图...
    jQuery plugins ...
    [转]asp.net文件下载方法...
    SQL SERVER 在做字符串比较时会自动去掉首尾空格?
    原来DataTable的Distinct竟如此简单!
    哎呀!可能有弹出式窗口拦截器生成Gmail无法打开该网页。如果您使用弹出式窗口拦截器,请将其关闭以便打开窗口。
    jquery的val() 的疑惑 ...
    [转].NET程序中打包安装程序中的卸载程序的制作
    小程序跳转页面选择数据
    dokcer kibana
  • 原文地址:https://www.cnblogs.com/123wang/p/6788802.html
Copyright © 2020-2023  润新知