您的位置:首页 > 其它

WPF入门教程(7)之双向数据绑定

2018-11-28 17:30 134 查看
版权声明:转载请注明出处 https://blog.csdn.net/junjunjiao0911/article/details/84584827

上篇我们已经了解了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窗口

阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: