zoukankan      html  css  js  c++  java
  • [uwp]数据绑定再学习

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

    出于某些原因,创建一个自定义控件(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下载点击这儿

  • 相关阅读:
    netty同时做http和websocket(netty入门)
    curl的概念及相关工具下载
    当删除某一个jar包时tomcat中出现problem encountered while deleting resources问题
    一个servlet处理多个请求或者叫方法
    在web中实现当前变量和前一个的比较
    URL中可以出现的字符
    在Editplus直接运行程序的步骤
    socket的相关知识理解
    011 python接口 bs4提取结果
    010 python接口 bs4解析html
  • 原文地址:https://www.cnblogs.com/cjw1115/p/5243200.html
Copyright © 2011-2022 走看看