WPF入门教程(7)之双向数据绑定
上篇我们已经了解了MVVM的框架结构和运行原理。这里我们来看一下伟大的双向数据绑定。双向绑定要表达的效果很简单:就是在界面的操作对数据模型的修改能实时反映到数据;而数据的变更能实时展现到界面。即视图数据模型(ViewModel)和视图(View)之间的双向绑定和触发。
我们尝试操作一下,边学习边写代码。
第一步:先写一个Model,里面包含我们需要的数据信息,代码如下(不会写Model的可参考WPF入门教程系列(4)):
[code]using GalaSoft.MvvmLight; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MVVMLightDemo.Model { public class UserInfoModel: ObservableObject { private String userName;//用户名称 public String UserName { get { return userName; } set { userName = value;RaisePropertyChanged(() => UserName); } } private Int64 userPhone;//用户电话 public Int64 UserPhone { get { return userPhone; } set { userPhone = value;RaisePropertyChanged(() => UserPhone); } } private Int32 userSex;//用户性别 public Int32 UserSex { get { return userSex; } set { userSex = value;RaisePropertyChanged(() => UserSex); } } private String userAdd;//用户地址 public String UserAdd { get { return userAdd; } set { userAdd = value;RaisePropertyChanged(() => UserAdd); } } } }
第二步:写一个ViewModel,包含了View所需要的命令和属性:
[code]using GalaSoft.MvvmLight; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using MVVMLightDemo.Model; namespace MVVMLightDemo.ViewModel { public class BothWayBindViewModel:ViewModelBase { public BothWayBindViewModel() { UserInfo = new UserInfoModel(); } #region 属性 /// <summary> /// 用户信息 /// </summary> private UserInfoModel userInfo; public UserInfoModel UserInfo { get { return userInfo; } set { userInfo = value;RaisePropertyChanged(() => UserInfo); } } #endregion #region 命令 #endregion } }
第三步:在ViewModelLocator中注册我们写好的ViewModel:SimpleIoc.Default.Register<BothWayBindViewModel>();
[code]/* In App.xaml: <Application.Resources> <vm:ViewModelLocatorTemplate xmlns:vm="clr-namespace:MVVMLightDemo.ViewModel" x:Key="Locator" /> </Application.Resources> In the View: DataContext="{Binding Source={StaticResource Locator}, Path=ViewModelName}" */ using GalaSoft.MvvmLight; using GalaSoft.MvvmLight.Ioc; using Microsoft.Practices.ServiceLocation; using MVVMLightDemo.Model; namespace MVVMLightDemo.ViewModel { /// <summary> /// This class contains static references to all the view models in the /// application and provides an entry point for the bindings. /// <para> /// See http://www.mvvmlight.net /// </para> /// </summary> public class ViewModelLocator { static ViewModelLocator() { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); if (ViewModelBase.IsInDesignModeStatic) { SimpleIoc.Default.Register<IDataService, Design.DesignDataService>(); } else { SimpleIoc.Default.Register<IDataService, DataService>(); } SimpleIoc.Default.Register<MainViewModel>(); SimpleIoc.Default.Register<BothWayBindViewModel>(); } /// <summary> /// Gets the Main property. /// </summary> [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "This non-static member is needed for data binding purposes.")] ///实例化 public MainViewModel Main { get { return ServiceLocator.Current.GetInstance<MainViewModel>(); } } public BothWayBindViewModel BothWayBind { get { return ServiceLocator.Current.GetInstance<BothWayBindViewModel>(); } } /// <summary> /// Cleans up all the resources. /// </summary> public static void Cleanup() { } } }
第四步:编写View
[code]<Window x:Class="MVVMLightDemo.View.BothWayBindView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" DataContext="{Binding Source={StaticResource Locator},Path=BothWayBind}" Title="BothWayBindView" Height="300" Width="300"> <Grid> <StackPanel Orientation="Vertical" Margin="10,10,0,0"> <StackPanel Orientation="Horizontal" > <TextBlock Text="请输入姓名:" ></TextBlock> <TextBox Text="{Binding UserInfo.UserName,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}" Width="200" ></TextBox> </StackPanel> <StackPanel Margin="0,10,0,0" Orientation="Horizontal" > <TextBlock Text="Hello " ></TextBlock> <TextBlock Text="{Binding UserInfo.UserName}" ></TextBlock> </StackPanel> <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal" > </StackPanel> </StackPanel> </Grid> </Window>
理论上效果应该如图所示(当修改输入框的内容的时候,对应绑定数据相应改变,并触发对UI的修改,所以下面那行文字也相应改变改变。):
<Window x:Class="MVVMLightDemo.View.BothWayBindView"
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:MVVMLightDemo.View"
mc:Ignorable="d"
DataContext="{Binding Source={StaticResource Locator},Path=BothWayBind}"
Title="BothWayBindView" Height="300" Width="300">
<Grid>
<StackPanel Orientation="Vertical" Margin="10,10,0,0">
<StackPanel Orientation="Horizontal">
<TextBlock Text="请输入姓名:">
</TextBlock>
<TextBox Text="{Binding UserInfo.UserName,UpdateSourceTrigger=PropertyChanged}"
Width="180" TextChanged="TextBox_TextChanged"></TextBox>
</StackPanel>
<StackPanel Margin="0,10,0,0" Orientation="Horizontal">
<TextBlock Text="Hello ">
</TextBlock>
<TextBlock Text="{Binding UserInfo.UserName,UpdateSourceTrigger=PropertyChanged}">
</TextBlock>
</StackPanel>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal"></StackPanel>
</StackPanel>
</Grid>
</Window>
如果你的文本内容不能同步更新,请注意红字部分,查看你是否添加了触发事件。
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。
最后总结一下,双向数据绑定的具体流程就是:建一个Model类->建一个ViewModel类->
在ViewModelLocator中注册我们写好的ViewModel:SimpleIoc.Default.Register<BothWayBindViewModel>();->建一个View窗口
阅读更多- Angular 4入门教程系列:3:Tour of Heroes之双向数据绑定
- WPF入门教程系列十五——WPF中的数据绑定(一)
- WPF入门教程系列十五——WPF中的数据绑定(一)
- WPF入门教程系列十六——WPF中的数据绑定(二)
- WPF入门教程系列十六——WPF中的数据绑定(二)
- WPF入门教程系列十七——WPF中的数据绑定(三)
- WPF入门教程系列十八——WPF中的数据绑定(四)
- WPF入门教程系列十七——WPF中的数据绑定(三)
- AngularJS入门教程之双向绑定详解
- AngularJS入门教程04:双向绑定
- WPF 4 中DataGrid的模板列做双向数据绑定
- ASP.NET入门教程:数据绑定
- AngularJS入门教程之数据绑定原理详解
- WPF教程(三十三)数据绑定简介
- 如何用javascript实现双向数据绑定 / Backbone.js简单入门范例
- 8天入门wpf—— 第五天 数据绑定
- vue教程1-01 v-model 一般表单元素(input) 双向数据绑定
- AngularJS入门教程之数据绑定用法示例
- WPF入门教程(8)之绑定和绑定的各种使用场景
- AngularJS入门心得2——何为双向数据绑定