在开始上代码前,先来假设这样一种情形:

出于某些原因,创建一个自定义控件(UserControl),然后为它定义一个依赖属性,这个属性有两个作用,一是调用控件方通过数据绑定技术为它赋值,二是控件内部的其他属性需要从这个自定义的属性获取数据。这个自定义的依赖属性充当的是一个中间件的作用。

用到的技术就是数据绑定和依赖属性。

针对这种情形,做一个例子如下:

这是充当中间件的Model,只有一个Name属性

public class Entity{
public string Name{get;set;}
}

 

自定义控件(这儿我给他起名为MyTextBox)的XAML代码如下:

<Grid>
<TextBox x:Name="textbox" Text="{Binding Data.Name,Mode=TwoWay}"></TextBox>
</Grid>

很简单,就一个TextBox,注意Text和Name绑定.

下面是MyTextBox对应的后台代码:

public sealed partial class MyTextBox : UserControl{
public MyTextBox(){
this.InitializeComponent();
this.textbox.DataContext = this;
}
public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(Entity), typeof(MyTextBox), new PropertyMetadata(null));
public Entity Data
{
get { return (Entity)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
}

这儿就用到了自定义依赖属性的知识,其实就是一个固定套路,但一定注意,在Data属性的get和set访问器中,最好不要添加额外的代码,因为不一定会执行的。因为在内部可以直接调用GetValue和SetValue来访问依赖属性DataProperty。这点可以去MSDN上查阅。

至于这句

this.textbox.DataContext=this;

待会儿再说,应该是比较核心的一句代码,当然也有变通方式。

至此,自定义的一个MyTextBox就完成了。

接着就要使用我们这个自定义的MyTextBox了,怎么用呢?接着看

我准备在MainPage中直接使用这个控件,但在这之前,先为MainPage定义一个ViewModel,顺便玩玩MVVM。

ViewModel如下:

public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged; private Entity _info;
public Entity Info
{
get { return _info; }
set { _info= value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Info")); }
}
}

这个结构应该很简单了,为ViewModel实现INotifyPropertyChanged接口,然后定义一个Entity类型的属性Info,在属性的Set访问其中,调用事件的Invoke方法(现在编译器会自动优化,所以这儿不存在线程安全的问题。),Entity是之前定义的一个Model类。

接着是MainPage的XAML了,。。

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<local:MyTextBox Data="{Binding Info,Mode=OneWay}" Height="50" VerticalAlignment="Stretch"></local:MyTextBox>
<Button Content="test" Click="Button_Click" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"></Button>
</Grid>

这儿为自定义属性Data做了一个数据绑定,结合上面的ViewModel,很显然,是把Data和ViewModel中的Info绑定了。
至于下面那个Button,是为了通过调试来查看数据绑定的效果来设置的。

然后就是最后的MainPage.cs了

    public sealed partial class MainPage : Page
{
ViewModel VM;
public MainPage()
{
this.InitializeComponent();
VM = new ViewModel();
this.DataContext = VM;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
//VM.Info = new Entity() { Name = "我心爱的姑娘" };
//VM.Info.Name = "你好吗";
//VM.Info= null;
}
}

因为是一个简单的MVVM嘛,所以先定义一个字段VM,然后再构造函数里把Page的DataContext设置为VM;
工作差不多了,接下来就是通过F9,F10还有那个Button来调试了。

下面一一列举:

1.当Button_Click中代码为

VM.Info= new Entity() { Name = "我心爱的姑娘" };

这一句时,会看到MainPage中的文本框里出现了“我心爱的姑娘”字样。

基本满足要求,继续···

2.当Button_Click中代码为

VM.Info= new Entity() { Name = "我心爱的姑娘" };
VM.Info.Name = "你好吗";

这次是不是会出现“你好吗”?执行完成后,会发现字样没变,依然是“我心爱的姑娘”.

为什么会这样呢?通过调试发现,Name在内存中的确是“你好吗”,只是界面上没有显示出来。答案待会儿解释。

3.当Button_Click中代码为

VM.Info= new Entity() { Name = "我心爱的姑娘" };
VM.Info= null;

这次执行完后,结果显而易见,文本框会一片空白。

现在来分析:ViewModel实现了INotifyPropertyChanged接口,而Entity并没有实现该接口.

Info定义在ViewModel里,在属性值改编后会会调用事件的Invoke方法通知系统,实现界面的同步。

Name定义在Entity中,值改变与否,都不会通知系统。

所以,如果想要让Name的值也同步显示,只需要为Entity实现INotifyPropertyChanged该接口即可。

好,说了一大堆,启示和我写博客的初衷并不相同,我是来解释这一句的

this.textbox.DataContext=this;

为什么要这么做呢?
在XAML的控件树中,DataContext是可以继承的。因为之前设置了Page的DataContext为VM,如果不加这一句的话,会导致自定义控件的DataContext也是VM,显然在VM里是找不到Data.Name的。

VM中只有Info.Name,当然,吧Info和Data改一致后,比如说都改为Data,那么的确表面上数据得到了绑定,但是却会深度耦合。

当然还有其他办法。

欢迎交流。

demo下载点击这儿

[uwp]数据绑定再学习的更多相关文章

  1. js再学习笔记

    #js再学习笔记 ##基本 1.js严格区分大小写   2.js末尾的分号可加,也可不加   3.六种数据类型(使用typeof来检验数据的类型) `typeof` - undefined: `var ...

  2. express再学习

    对比spring,django,再学习express就有很多共通的地方啦... 看的书是一本小书,<express in action>,排版比较好. 昨天开始看,看了快四分之一啦... ...

  3. Android再学习-20141023-Intent-Thread

    20141023-Android再学习 Intent对象的基本概念 Intent是Android应用程序组件之一 Intent对象在Android系统中表示一种意图 Intent当中最重要的内容是ac ...

  4. Android再学习-20141022-Activity的生命周期

    20141022-Android再学习 如何在一个应用程序当中定义多个Activity 定义一个类,继承Activity 在该类当中,复写Activity当中的onCreate方法.onCreate( ...

  5. Android再学习-20141018-布局-进度条

    20141018-Android再学习 对齐至控件的基准线 为了保证印刷字母的整齐而划定的线(四线三格的第三条线). android:layout_alignBaseline 与父控件的四个边缘对齐( ...

  6. 再学习sqlhelper

    在机房收费重构系统的时候,第一次学习sqlhelper.当时感觉比较简单,没有写博客总结,现在又经过了图书馆的学习,感觉还是有必要写一写的. SqlHelper是一个基于.NETFramework的数 ...

  7. c/c++再学习:常用字符串转数字操作

    c/c++再学习:常用字符串转数字操作 能实现字符串转数字有三种方法,atof函数,sscanf函数和stringstream类. 具体demo代码和运行结果 #include "stdio ...

  8. c/c++再学习:C与Python相互调用

    c/c++再学习:Python调用C函数 Python 调用C函数比较简单 这里两个例子,一个是直接调用参数,另一个是调用结构体 C代码 typedef struct { int i1; int i2 ...

  9. MQTT再学习 -- MQTT 客户端源码分析

    MQTT 源码分析,搜索了一下发现网络上讲的很少,多是逍遥子的那几篇. 参看:逍遥子_mosquitto源码分析系列 参看:MQTT libmosquitto源码分析 参看:Mosquitto学习笔记 ...

随机推荐

  1. javaweb消息中间件——rabbitmq入门

    概念:RabbitMQ是一款开源的消息中间件系统,由erlang开发,是AMQP的实现. 架构图大概如上. broker是消息队列的服务器,比如在linux上,我们安装的rabbitmq就是一个bro ...

  2. 基于sersync海量文件实时同步

    项目需求:最近涉及到数百万张图片从本地存储迁移到云存储,为了使完成图片迁移,并保证图片无缺失,业务不中断,决定采用实时同步,同步完后再做流量切换.在实时同步方案中进行了几种尝试. 方案1:rsync+ ...

  3. React-Todos

    最近学完React的最基本概念,闲下来的时候就自己写了一个Todo-List的小应用.这里做个简略的说明,给想好好学React的新手看. React-Todo 学习前提 这里我用了webpackb做了 ...

  4. JSF + Primefaces: Problem with “rendered” components with ajax

    Cant seem to get rendered to work correctly with update attributes. Here is my codes <ui:define n ...

  5. Shadow Mapping 的原理与实践 【转】

    早在上世纪七十年代末,Williams在他的“Casting Curved Shadows on Curved Surface”一文中提出了名为Shadow Map的阴影生成技术.之后,他人在此基础上 ...

  6. 迷你MVVM框架 avalonjs 0.97发布

    在本版本中,王之三柱臣全部就位! mmRouter: https://github.com/RubyLouvre/mmRouter mmAnimate: https://github.com/Ruby ...

  7. swagger2 注解整体说明

    @Api:用在请求的类上,表示对类的说明 tags="说明该类的作用,可以在UI界面上看到的注解" value="该参数没什么意义,在UI界面上也看到,所以不需要配置&q ...

  8. 读取和反序列化Hadoop二进制文件

    目录 问题描述 反序列化代码 问题描述 Hadoop在运行MR时,经常要将一些中间结果存到本地,为了节省存储空间,Hadoop采用序列化机制(Hadoop的序列化机制和Java的有所不同)将数据保存为 ...

  9. MVC表单提交写法1

    初学MVC,感觉跟以前的aspx页面差别很大,我们就先来看看MVC的表单是怎么提交的吧. 现在我们用一个最简单的例子来看一看MVC是怎么提交表单的(这一个例子中,我们的关注点是如何提交表单,所以不涉及 ...

  10. 10G个64bit整数,找出中位数

    [10G个64bit整数,找出中位数] 题目:在一个文件中有10G个64bit整数,乱序排列,要求找出中位数.内存限制为2G. 解法:内存限制为2G表面上是限制,实际上是一种提示,在提示我们如何利用2 ...