热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

WPF之Binding初探

  初学wpf,经常被Binding搞晕,以下记录写Binding的基础。首先,盗用张图。这图形象的说明了Binding的机理。对于Binding,意思是数据绑定,基本用法是:1、

 

 

初学wpf,经常被Binding搞晕,以下记录写Binding的基础。

首先,盗用张图。这图形象的说明了Binding的机理。

WPF之Binding初探

对于Binding,意思是数据绑定,基本用法是:

1、在xmal中使用

  如下,在TextBox上绑定了Slider的Value,WPF将会机智的进行双向绑定,即TextBox和Slider中任何一方改变,另外一方也将更随跟新。

        <TextBox Height="20" Margin="0,0,10,87" Text="{Binding ElementName=slider1,Path=Value}" BorderThickness="1"/>
        <Slider Maximum="100" Margin="0,50,0,35" Name="slider1"/>

上面的TextBox相当与下面的。Mode就是数据绑定的方向。

控制Binding数据流向的属性是Model,它的类型是BindingModel的枚举。BindingModel可以取值为TwoWay、OneWay、OneTime、OneWayToSource和Default。这里的Default指的是Binding的模式会根据目标是实际情况来确定,如果是可以编辑的(TextBox的Text属性),Default就采用双向模式。如果是TextBlock,不可编辑,就使用单向模式。

如果我们在TextBox里面输入一个恰当的值按Tab键、让焦点离开TextBox,则Slider手柄就会跳转至相应的值那里。

为什么一定要在TextBox失去焦点以后才改变值呢?这就引出了Binding的另外一个属性-----UpdateSourceTrigger,它的类型是UpdateSourceTrigger枚举,可取值为PropertyChanged、LostFous、Explicit和Default。显然,对于Text的Default行为与LostFocus一致,我们只需要把这个值改成PropertyChanged,则Slider就会随着输入值的变化而变化了。

即加入以下带代码:

UpdateSourceTrigger=PropertyChanged
注意:
顺便提一句,Binding还具有NotifyOnSourceUpdated属性和NotifyOnTargetUpdated两个bool类型是属性。如果设置为True,则在源或目标被更新以后就会触发相应的SourceUpdated事件和TargetUpdated事件。实际工作中我们可以监听这两个事件来找出来哪些数据或控件被更新了。

2、在后台c#代码中使用

等效与上面的代码

  this.textbox1.SetBinding(TextBox.TextProperty, new Binding("Value") { ElementName = slider1.Name,Mode=BindingMode.TwoWay});

  或者是  

  this.textbox1.SetBinding(TextBox.TextProperty, new Binding("Value") { Source=slider1, Mode = BindingMode.TwoWay });

这里的ElementName与Source之间是有区别的,Source是object类型的,能接受的是一个对象,而ElementName是string型的,之恩能够接受名称。下面这样做是不行地

WPF之Binding初探

3、Binding的数据校验

inding的ValidationRules属性是Collection,从它的名称和数据类型我们可以得知可以为每个Binding设置多个数据校验条件,每一个条件是一个ValidationRule对象。ValidationRule是一个抽象类,在使用的时候我们需要创建它的派生类并实现它的Validate方法的返回值是ValidateionResult类型对象,如果通过验证,就把ValidateionResult对象的IsValidate属性设为true,反之,则需要将IsValidate设置为false并为其ErrorContent属性设置一个合适的消息内容(一般是字符串)。
下面这个程序的UI绘制一个TextBox和一个Slider,然后在后台C#代码中建立Binding把它们关联起来---- 已Slide为源,TextBox为目标。Slider的取值范围是0~100,也就是说我们需要验证TextBox中输入的值是不是在0~100之间。

先定义一个ValidationRule的子类。

    class RangeValidationRule : ValidationRule
    {
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            double d = 0;
            if (double.TryParse(value.ToString(), out d))
            {
                if (d >= 0 && d <= 100)
                {
                    return new ValidationResult(true, null);
                }
            }
            return new ValidationResult(false, "ErrorContent");
        }
    }

然后在后台C#代码中这样定义binding。

 

Binding bind =new Binding("Value") { UpdateSourceTrigger= UpdateSourceTrigger.PropertyChanged,Source=slider1, Mode= BindingMode.TwoWay};            ValidationRule rule = new RangeValidationRule();  

rule.ValidatesOnTargetUpdated = true;  

bind.ValidationRules.Add(rule); 

至于怎么在xmal中实现上面的数据校验,我还没做过,等有时间在探索。

4、关于path

尽管在XAML代码中或者Binding类的构造器参数列表中我们使用字符串来表示Path,但Path的实际类型是PropertyPath。

这样用获取Text的长度属性

Binding Path=Text.Length,ElementName=textBox1,Mode=OneWay

 

获取第四个字符

Binding Path=Text[3]

 

有的时候我们会在代码中我们看大Path是一个“.”或者干脆没有Path的Binding,着实让人摸不着头脑。原来这是一种比较特殊的情况---Binding源本身就是一种数据且不需要Path来指明。典型的string,int等基本类型都是这样,他们是实例本身就是数据,我们无法指定通过那个属性来访问这个数据,这是我们只需要将这个数据设置为.就可以了。在XAML中这个.可以忽略不写,但是在C#中编程必须要带上。

   <StackPanel Height="184" Name="stackPanel1" Width="288">  
            <StackPanel.Resources>  
                <String:String x:Key="myString">  
                    菩提本无树,何处染尘埃。  
          String:String>  
              
       StackPanel.Resources>  
        <TextBlock Height="23" Name="textBlock1" Text="{Binding Path=.,Source={StaticResource ResourceKey=myString}}" />  
    StackPanel>  

或者

<TextBlock Height="23" Name="textBlock1" Text="{Binding .,Source={StaticResource ResourceKey=myString}}" /> 

或者

<TextBlock Height="23" Name="textBlock1" Text="{Binding Source={StaticResource ResourceKey=myString}}" />

后台C#写法

 string myString = "菩提本无树,明镜亦无台。本来无一物,何处染尘埃。";
this.textBlock1.SetBinding(TextBlock.TextProperty, new Binding(".") { Source=myString});

5、最后,谈谈数据绑定一点心得

wpf的数据绑定主要是为了达到数据驱动UI的目的,说到底,还是为了通知UI,数据已经改变了。。。。

WPF的绝大多数控件都实现了INotifyPropertyChanged,所以当我们绑定两个控件时,一个控件的值改变,另一个的值也就能实时更新,这样才有了我们在上面的TextBox和Slider中改变任意一个的值,另外一个实时改变,这里为了做个验证,我在Slider上绑定一个实例属性,看看属性的值改变的时候Slider的值是不是跟着改变,理论上是不会的。

        public MainWindow()
        {
            InitializeComponent();
            //this.textbox1.SetBinding(TextBox.TextProperty, new Binding("Value") { ElementName = slider1.Name, Mode = BindingMode.TwoWay });
            this.slider1.SetBinding(Slider.ValueProperty, new Binding(".") { Source = ChangeValue });
            //ValidationRule rule = new RangeValidationRule();
            //rule.ValidatesOnTargetUpdated= true;
            

        }
        private int changeValue=20;

        public int ChangeValue
        {
            get { return changeValue; }
            set { changeValue = value; }
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            changeValue += 10;
        }

单击button并没有发现Slider的值跟着改变,这里说明ChangeValue并不是依赖属性的前提下并不能实时通知UI的Slider,自己的值改变的事。

这里就引出了依赖属性的学习。如果吧ChangeValue定义成依赖属性,就可以是实现实时通知UI的功能了。

6、在5中,我们将clr属性绑定到Slider后,发现clr属性的值改变的时候Slider的值并不会跟着改变。说明clr属性并不具有实时通知UI界面的能力。这里,我知道2种方法实现这种实时通知的功能。一种是继承INotifyPropertyChanged接口,这个接口的实现在MVVM架构里面经常拿来使用。另外一种就是WPF的依赖属性来实现了。尽管MainWindow类没有实现INotifyPropertyChanged接口,当属性的值发送改变时与之关联的binding对象依然可以得到通知,依赖属性默认的带有这种功能,天生就是合格的数据源。

我们看下用下面的代码

xmal:

<TextBox Name="textbox1" Height="20" Margin="0,0,10,87" BorderThickness="1"/>
        <Slider Maximum="100" Margin="0,50,0,35" Name="slider1"/>
        <Button Width="100" Height="20" Margin="10,87,407,0" Click="Button_Click_1">Button>

c#:

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            //this.textbox1.SetBinding(TextBox.TextProperty, new Binding("Value") { ElementName = slider1.Name, Mode = BindingMode.TwoWay });
            this.slider1.SetBinding(Slider.ValueProperty, new Binding("changeValue") { Source = this, Mode = BindingMode.TwoWay });
            this.textbox1.SetBinding(TextBox.TextProperty, new Binding(".") { Source = clrValue });
            //this.textbox1.SetBinding(TextBox.TextProperty, new Binding("clrValue") { Source = this });//这样写的话程序运行时textbox1是空白,不显示clrValue的初始化值
            //ValidationRule rule = new RangeValidationRule();
            //rule.ValidatesOnTargetUpdated= true;
            

        }

        private string clrValue="10";

        public string ClrValue
        {
            get { return clrValue; }
            set { clrValue = value; }
        }

        public string changeValue
        {
            get { return (string)GetValue(changeValueProperty); }
            set { SetValue(changeValueProperty, value); }
        }

        // Using a DependencyProperty as the backing store for changeValue.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty changeValueProperty =
            DependencyProperty.Register("changeValue", typeof(string), typeof(MainWindow), new PropertyMetadata("20"));

        
        //private int changeValue=20;
        //public int ChangeValue
        //{
        //    get { return changeValue; }
        //    set { changeValue = value; }
        //}

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            clrValue = "80";
            changeValue = "50";
        }
        
    }

上面的代码定义了一个clr属性clrValue和一个依赖属性changeValue,依赖属性绑定到Slider上,clr属性绑定到textbox上,button单击是两个属性的值都发生了变化,我们看看哪个的变化能实时通知到UI界面上。

 程序运行时:

WPF之Binding初探

单击button后,发现textbox里面的值没变,而slider的值变了,说明依赖属性的值改变了能实时通知到UI。这就能力对于clr属性来说本身是没有的,如果clr属性的类实现了INotifyPropertyChange接口,那它也就具有这种能力。

WPF之Binding初探

 

一个类实现INotifyPropertyChanged接口,线面是最简的实现

  class NotificationObject:INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

然后需要具有通知UI能力的类只需继承自这个类就行了,这个Model的Myproperty的改变就能实现通知UI了

class Model : NotificationObject
    {
        private string _MyProperty = "Hello!";

        public string Myproperty
        {
            get { return _MyProperty; }
            set
            {
                _MyProperty = value;
                this.RaisePropertyChanged("Myproperty");
            }
        }

        public void Copy(object obj)
        {
            this.Myproperty += " en,Hello!";
        }
    }

 

 7、就上面6中的数据绑定而言,我有一些不解,先记录下来,等以后彻底理解了就来详细说明。

看代码

this.slider1.SetBinding(Slider.ValueProperty, new Binding("changeValue") { Source = this, Mode = BindingMode.TwoWay });
//this.slider1.SetBinding(Slider.ValueProperty, new Binding(".") { Source = changValue, Mode = BindingMode.TwoWay });//这样写不能实现实时通知UI
this.textbox1.SetBinding(TextBox.TextProperty, new Binding(".") { Source = clrValue }); 
//this.textbox1.SetBinding(TextBox.TextProperty, new Binding("clrValue") { Source = this });//这样写的话程序运行时textbox1是空白,不显示clrValue的初始化值

在上面的代码中,我发现对于依赖属性,如果使用第一行的写法,也就是Binding的双引号里面放属性名,Source里面放this,可以实现实时通知UI的功能,如果按照第二行的
写法,程序运行时能显示changeValue的初始值,而不能实现
通知UI值改变的功能。
而对于clr属性来说,也就是Binding的双引号里面放点,Source里面放属性名,这样才能在程序运行时让textbox显示属性的值,乳沟按第二种写法,textbox显示的是空白。
以上两种写法导致的的差异的原因,作为新学的我来说还是不能理解,希望能尽快搞懂。
写博客真费功夫以上内容参考了很多深入浅出WPF中的内容。



推荐阅读
  • 设计实战 | 10个Kotlin项目深度解析:首页模块开发详解
    设计实战 | 10个Kotlin项目深度解析:首页模块开发详解 ... [详细]
  • Python 实战:异步爬虫(协程技术)与分布式爬虫(多进程应用)深入解析
    本文将深入探讨 Python 异步爬虫和分布式爬虫的技术细节,重点介绍协程技术和多进程应用在爬虫开发中的实际应用。通过对比多进程和协程的工作原理,帮助读者理解两者在性能和资源利用上的差异,从而在实际项目中做出更合适的选择。文章还将结合具体案例,展示如何高效地实现异步和分布式爬虫,以提升数据抓取的效率和稳定性。 ... [详细]
  • SQLite数据库CRUD操作实例分析与应用
    本文通过分析和实例演示了SQLite数据库中的CRUD(创建、读取、更新和删除)操作,详细介绍了如何在Java环境中使用Person实体类进行数据库操作。文章首先阐述了SQLite数据库的基本概念及其在移动应用开发中的重要性,然后通过具体的代码示例,逐步展示了如何实现对Person实体类的增删改查功能。此外,还讨论了常见错误及其解决方法,为开发者提供了实用的参考和指导。 ... [详细]
  • 探索偶数次幂二项式系数的求和方法及其数学意义 ... [详细]
  • 本文深入探讨了CGLIB BeanCopier在Bean对象复制中的应用及其优化技巧。相较于Spring的BeanUtils和Apache的BeanUtils,CGLIB BeanCopier在性能上具有显著优势。通过详细分析其内部机制和使用场景,本文提供了多种优化方法,帮助开发者在实际项目中更高效地利用这一工具。此外,文章还讨论了CGLIB BeanCopier在复杂对象结构和大规模数据处理中的表现,为读者提供了实用的参考和建议。 ... [详细]
  • 如何高效启动大数据应用之旅?
    在前一篇文章中,我探讨了大数据的定义及其与数据挖掘的区别。本文将重点介绍如何高效启动大数据应用项目,涵盖关键步骤和最佳实践,帮助读者快速踏上大数据之旅。 ... [详细]
  • 本文详细介绍了 jQuery 的入门知识与实战应用,首先讲解了如何引入 jQuery 库及入口函数的使用方法,为初学者提供了清晰的操作指南。此外,还深入探讨了 jQuery 在实际项目中的多种应用场景,包括 DOM 操作、事件处理和 AJAX 请求等,帮助读者全面掌握 jQuery 的核心功能与技巧。 ... [详细]
  • 掌握Android UI设计:利用ZoomControls实现图片缩放功能
    本文介绍了如何在Android应用中通过使用ZoomControls组件来实现图片的缩放功能。ZoomControls提供了一种简单且直观的方式,让用户可以通过点击放大和缩小按钮来调整图片的显示大小。文章详细讲解了ZoomControls的基本用法、布局设置以及与ImageView的结合使用方法,适合初学者快速掌握Android UI设计中的这一重要功能。 ... [详细]
  • 技术分享:深入解析GestureDetector手势识别机制
    技术分享:深入解析GestureDetector手势识别机制 ... [详细]
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
  • 本文介绍了如何利用Apache POI库高效读取Excel文件中的数据。通过实际测试,除了分数被转换为小数存储外,其他数据均能正确读取。若在使用过程中发现任何问题,请及时留言反馈,以便我们进行更新和改进。 ... [详细]
  • 在处理遗留数据库的映射时,反向工程是一个重要的初始步骤。由于实体模式已经在数据库系统中存在,Hibernate 提供了自动化工具来简化这一过程,帮助开发人员快速生成持久化类和映射文件。通过反向工程,可以显著提高开发效率并减少手动配置的错误。此外,该工具还支持对现有数据库结构进行分析,自动生成符合 Hibernate 规范的配置文件,从而加速项目的启动和开发周期。 ... [详细]
  • Spring框架中的面向切面编程(AOP)技术详解
    面向切面编程(AOP)是Spring框架中的关键技术之一,它通过将横切关注点从业务逻辑中分离出来,实现了代码的模块化和重用。AOP的核心思想是将程序运行过程中需要多次处理的功能(如日志记录、事务管理等)封装成独立的模块,即切面,并在特定的连接点(如方法调用)动态地应用这些切面。这种方式不仅提高了代码的可维护性和可读性,还简化了业务逻辑的实现。Spring AOP利用代理机制,在不修改原有代码的基础上,实现了对目标对象的增强。 ... [详细]
  • 本文探讨了利用Java实现WebSocket实时消息推送技术的方法。与传统的轮询、长连接或短连接等方案相比,WebSocket提供了一种更为高效和低延迟的双向通信机制。通过建立持久连接,服务器能够主动向客户端推送数据,从而实现真正的实时消息传递。此外,本文还介绍了WebSocket在实际应用中的优势和应用场景,并提供了详细的实现步骤和技术细节。 ... [详细]
  • 通过 NuGet 获取最新版本的 Rafy 框架及其详细文档
    为了帮助开发者更便捷地使用Rafy领域实体框架,我们已将最新版的Rafy框架程序集上传至nuget.org,并同步发布了最新版本的Rafy SDK至Visual Studio。此外,我们还提供了详尽的文档和示例,以确保开发者能够快速上手并充分利用该框架的强大功能。 ... [详细]
author-avatar
将登太行的2602939913
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有