WPF入门教程系列十三——依赖属性(三)

四、 只读依赖属性

  在以前在对于非WPF的功能来说,对于类的属性的封装中,经常会对那些希望暴露给外界只读操作的字段封装成只读属性,同样在WPF中也提供了只读属性的概念,如一些 WPF控件的依赖属性是只读的,它们经常用于报告控件的状态和信息,像IsMouseOver等属性, 那么在这个时候对它赋值就没有意义了。 或许你也会有这样的疑问:为什么不使用一般的.Net属性提供出来呢?一般的属性也可以绑定到元素上呀?这个是由于有些地方必须要用到只读依赖属性,比如 Trigger等,同时也因为内部可能有多个提供者修改其值,所以用.Net属性就不能完成天之大任了。
  那么一个只读依赖属性怎么创建呢?其实创建一个只读的依赖属性和创建一个一般的依赖属性大同小异。不同的地方就是DependencyProperty.Register变成了DependencyProperty.RegisterReadOnly。和前面的普通依赖属性一样,它将返回一个 DependencyPropertyKey。而且只提供一个GetValue给外部,这样便可以像一般属性一样使用了,只是不能在外部设置它的值罢了。

下面我们就用一个简单的例子来概括一下:

public partial class WindowReadOnly : Window{public WindowReadOnly (){InitializeComponent();//用SetValue的方法来设置值DispatcherTimer timer =new DispatcherTimer(TimeSpan.FromSeconds(1),DispatcherPriority.Normal,(object sender, EventArgs e)=>{int newValue = Counter == int.MaxValue ? 0 : Counter + 1;SetValue(counterKey, newValue);},Dispatcher);}//属性包装器,只提供GetValuepublic int Counter{get { return (int)GetValue(counterKey.DependencyProperty); }}//用RegisterReadOnly来代替Register来注册一个只读的依赖属性private static readonly DependencyPropertyKey counterKey =DependencyProperty.RegisterReadOnly("Counter",typeof(int),typeof(WindowReadOnly),new PropertyMetadata(0));}

 

 

  
XAML代码:

<Window x:Name="winReadOnly" x:Class="WpfApp1.WindowReadOnly"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"Title="WindowDepend" Height="300" Width="300"><Grid><Viewbox><TextBlock Text="{Binding ElementName=winReadOnly, Path=Counter}" /></Viewbox></Grid>
</Window>

 

 

效果如下图所示: 

 

五、 附加属性

      现在我们再继续探讨另外一种特殊的依赖属性——附加属性。附加属性是一种特殊的依赖属性。这是WPF的特性之一,通俗的理解起来就是,别人有的属性,由于你跟他产生了关系所以你也有了这个属于他的属性。

      附加属性是说一个属性本来不属于某个对象,但由于某种需求而被后来附加上,也就是把对象放入一个特定环境后对象才具有的属性就称为附加属性,附加属性的作 用就是将属性与数据类型解耦,让数据类型的设计更加灵活,举例,一个TextBox被放在不同的布局容器中时就会有不同的布局属性,这些属性就是由布局容 器为TextBox附加上的,附加属性的本质就是依赖属性,二者仅仅在注册和包装器上有一点区别。  

      附加属性是依赖属性的一种特殊形式,它可以让用户在一个元素中设置其他元素的属性。一般来说,附加属性是用于一个父元素定位其他元素布局 的。就像Grid和DockPanel元素就包含附加属性。Grid使用附加属性来指定包含子元素的特定行和列,而DockPanel使用附加属性是来指 定子元素应该停靠在面板中的何处位置。

      附加属性就是自己没有这个属性,在某些上下文中需要就被附加上去。比如StackPanel的Grid.Row属性,如果我们定义StackPanel类时定义一个Row属性是没有意义的,因为我们并不知道一定会放在Grid里,这样就造成了浪费。

例如,下面转场控件的定义使用了Grid的Row属性来将自身定位到特定的行中。

   <Grid><Grid.RowDefinitions><RowDefinition Height="101*"/><RowDefinition Height="80"/><RowDefinition Height="80"/></Grid.RowDefinitions><StackPanel Grid.Row="0" >

 

 

     尽管对于一个普通的WPF开发人员来说,理解依赖和附加属性并不一定是必须的,但是掌握好WPF系统的整个运行机制对于提升WPF应用技术是非常重要的。

     使用附加属性,可以避开可能会防止一个关系中的不同对象在运行时相互传递信息的编码约定。一定可以针对常见的基类设置属性,以便每个对象只需获取和 设置该属性即可。但是,你可能希望在很多情况下这样做,这会使你的基类最终充斥着大量可共享的属性。它甚至可能会引入以下情况:在数百个后代中,只有两个 后代尝试使用一个属性。这样的类设计很糟糕。为了解决此问题,我们使用附加属性概念来允许对象为不是由它自己的类结构定义的属性赋值。在创建对象树中的各 个相关对象之后,在运行时从子对象读取此值。

  最好的例子就是布局面板。每一个布局面板都需要自己特有的方式来组织它的子元素。如Canvas需要Top和left来布 局,DockPanel需要Dock来布局。当然你也可以写自己的布局面板(在上一篇文章中我们对布局进行了比较细致的探讨,如果有不清楚的朋友也可以再 回顾一下)。

    下面代码中的Button 就是用了Canvas的Canvas.Top和Canvas.Left="20" 来进行布局定位,那么这两个就是传说中的附加属性。

<Canvas><Button Canvas.Top="20" Canvas.Left="20" Content="Knights Warrior!"/>
</Canvas>

 

  定义附加属性的方法与定义依赖属性的方法一致,前面我们是使用DependencyProperty.Register来注册一个依赖属性,只是在注册属性时使用的是RegisterAttach()方法。这个RegisterAttached的参数和 Register是完全一致的,那么Attached(附加)这个概念又从何而来呢?

  其实我们使用依赖属性,一直在Attached(附加)。我们注册(构造)一个依赖属性,然后在DependencyObject中通过 GetValue和SetValue来操作这个依赖属性,也就是把这个依赖属性通过这样的方法关联到了这个DependencyObject上,只不过是 通过封装CLR属性来达到的。那么RegisterAttached又是怎样的呢?

下面我们来看一个最简单的应用:首先我们注册(构造)一个附加属性

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows;using System.Windows.Media;namespace WpfApp1.Services{public class TurnoverManager : DependencyObject{//通过静态方法的形式暴露读的操作public static double GetAngle(DependencyObject obj){return (double)obj.GetValue(AngleProperty);}//通过静态方法的形式暴露写的操作public static void SetAngle(DependencyObject obj, double value){obj.SetValue(AngleProperty, value);}//通过使用RegisterAttached来注册一个附加属性public static readonly DependencyProperty AngleProperty =DependencyProperty.RegisterAttached("Angle", typeof(double), typeof(TurnoverManager), new PropertyMetadata(0.0, OnAngleChanged));//根据附加属性中的值,当值改变的时候,旋转相应的角度。private static void OnAngleChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e){var element = obj as UIElement;if (element != null){element.RenderTransformOrigin = new Point(0.5, 0.5);element.RenderTransform = new RotateTransform((double)e.NewValue);}}     }}

 

然后,我们在程序中使用这个我们自己定义的附加属性

<Window x:Class="WpfApp1.WindowTurnover"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:WpfApp1.Services"Title="WindowTurnover" Height="400" Width="500" Loaded="Window_Loaded"><Grid><Grid.RowDefinitions><RowDefinition Height="313*"/><RowDefinition Height="57*"/></Grid.RowDefinitions><Canvas Grid.Row="0"><Ellipse Name="ellipseRed" Fill="Red" Width="100" Height="60" Canvas.Left="56"Canvas.Top="98" local:TurnoverManager.Angle="{Binding ElementName=sliderAngle, Path=Value}"/><Rectangle Name="ellipseBlue" Fill="Blue" Width="80" Height="80" Canvas.Left="285"Canvas.Top="171" local:TurnoverManager.Angle="45" /><Button  Name="btnWelcome" Content="欢迎光临" Canvas.Left="265" Canvas.Top="48" FontSize="20" local:TurnoverManager.Angle="60"/></Canvas><WrapPanel Grid.Row="1"><Label Content="角度大小" /><Slider x:Name="sliderAngle" Minimum="0" Maximum="240" Width="300" /></WrapPanel></Grid></Window>

在XAML中就可以使用刚才注册(构造)的附加属性了:如下图。

通过调整角度值,显示不同的效果如下两图。图1,图2。

 

                               图1

 

                          图2

 

  

转载于:https://www.cnblogs.com/chillsrc/p/4661658.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/273104.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java 反编译 类名_java javassist创建类和反编译类

public class Byte {public static void main(String[] args) throws Exception {//获得类池ClassPool poolClassPool.getDefault();//创建类CtClass ccpool.makeClass("cn.sxt.in.Emp");//创建属性CtField f1 CtField.make("private int empno;", cc);Ct…

java生成动态验证码_动态生成验证码案例

servlet代码package cn.guizimo.web.servlet;import javax.imageio.ImageIO;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.…

TCP、UDP、HTTP、SOCKET之间的区别

http://blog.csdn.net/magister_feng/article/details/8634518 转载于:https://www.cnblogs.com/luningning0901/p/4667733.html

特征选择算法java实现_relief算法特征选择

1.[文件]Relief算法程序.txt ~ 6KB下载(44)package com.relief.algorithm;import java.util.Random;import java.util.Set;import java.util.ArrayList;import java.util.Collections;import java.util.HashMap;import java.util.List;import java.util.Map;public class Relie…

freemarker跳出循环

break语句跳出当前循环&#xff0c;如下: <#list table.columns as c> <#if c.isPK> <#assign pkNamec.columnName?cap_first /> <#break> </#if> </#list>转载于…

多线程程序排错总结

先不考虑其他因素&#xff0c;直接干掉密集IO操作&#xff0c;把并行IO变成串行IO 要沉下心来&#xff0c;先浏览一遍代码&#xff0c;看看是否有有问题的地方&#xff0c;首先找加锁的地方 没有办法的办法是&#xff0c;用二分法&#xff0c;一行一行的来定位转载于:https://w…

java如何将数据保存为xml6_用Java实现可保存状态的数据库生成XML树,源码来了(9)...

用Java实现可保存状态的数据库生成XML树&#xff0c;源码来了(9)时间&#xff1a;2006/7/19 5:38:30作者&#xff1a;佚名人气&#xff1a;306.3.2.Servlet源码1.RefreshServlet.javapackage com.sitechasia;import javax.servlet.*;import javax.servlet.http.*;import java.i…

企业服务总线全双工异步通信机

为了实现系统的高可靠性、高可用性和并行处理能力&#xff0c;我们经常使用一些负载均衡设备&#xff08;例如F5&#xff09;等集群解决方案。但&#xff0c;会有一些特殊的情况下&#xff0c;。例如&#xff0c;长连接、特殊的技术协议。不可用F5和其他设备来解决&#xff0c;…

java druid jdbc例子_JDBC【使用Druid连接数据库,DBUtils工具类的使用】

Druid连接数据库&#xff0c;DBUtils工具类的使用1.在maven中添加Druid依赖com.alibabadruid1.2.02.封装Druid连接方法import com.alibaba.druid.pool.DruidDataSource;import com.alibaba.druid.pool.DruidDataSourceFactory;import java.io.IOException;import java.io.Input…

TimerTask定时任务

web.xml <listener><listener-class>com.sign.listener.NFDFlightDataTaskListener</listener-class></listener> 监听器类 package com.sign.listener;import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener;impor…

java前后端接口文档_前后端交互接口设计规范

在开发web应用的时候&#xff0c;往往会涉及到一个问题&#xff0c;前端后接口定义的问题。接口定义设计的好坏很大程度上能影响一个项目的进度和可扩展性。但是前辈们在这个问题上留下了非常宝贵的一些常规的设计思路&#xff0c;值得我们参考。1、后端设计统一的返回模型在与…

2015 多校第三场

1002 求max&#xff08;f(a),f(b)&#xff09;, f为不重复的素因子个数&#xff0c; 在数据要求以内 &#xff0c; 每个数最多有7个&#xff0c;可以打表。 1 /*Author :usedrose */2 /*Created Time :2015/7/29 11:32:09*/3 /*File Name :2.cpp*/4 #include <cstdio>5 …

java多线程必须掌握吗_多线程模式有什么作用(java多线程必须掌握的知识)

什么叫多进程&#xff1f;在预估中&#xff0c;过程是已经实行的计算机语言的一个案例。或是简易地说&#xff0c;运作程序流程也称之为过程。多进程代表着“在单独计算机软件中具备2个或更好几个CPU。比如&#xff0c;假如计算机软件具备双核四线程&#xff0c;而且另外运作(实…

java配置irport,一个production模式下的Ror环境搭建-airport -JavaEye技术社区

比较了一些ROR的生产环境&#xff0c;经过测试&#xff0c;还是选用了mongrelapache的方式。1.download安装包:httpd-2.2.3.tar.gz ,apache服务器ruby-1.8.5.tar.gzrubygems-0.9.0.tgzmongrel-0.3.13.4.gem2.安装rubytar zxvf ruby-1.8.5.tar.gz./configuremakemake install3.安…

php ?redis,PHP使用Redis存储Session

对于大访问量的网站来说&#xff0c;会有许多的客户端和服务端建立链接&#xff0c;就会生成许多 Session 文件&#xff0c;由于 Session 文件是存储在硬盘上的&#xff0c;因此每次服务器去读取这些 Session 文件都要经过许多的 I/O 操作。PHP 中可使用 session_set_save_hand…

微信支付现金红包接口(转)

微信支付现金红包接口正式开放&#xff0c;只需开通微信支付&#xff0c;即可接入现金红包。通过现金红包接口&#xff0c;公众号开发者可以策划相关运营活动&#xff0c;向用户发放微信支付现金红包&#xff0c;更好的达到品牌推广及回馈用户的效果。具体能力如下&#xff1a;…

php 打印对象到文件,php实现将数组或对象写入到文件的方法小结【三种方法】...

本文实例讲述了php实现将数组或对象写入到文件的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;php将数组或对象原样写入或保存到文件有三种方法可以实现第一种方法是使用serialize&#xff0c;第二种方法是使用print_r&#xff0c;第三种方法是使用var_export&a…

The return types for the following stored procedures could not be detected

1、使用dbml映射数据库&#xff0c;添加存储过程到dbml文件时报错。 2、原因&#xff1a;存储过程中使用了临时表 3、解决方案 3.1 通过自定义表值变量实现 Ex: DECLARE TempTable TABLE ( AttributeID INT, Value NVARCHAR(200) ) INSERT INTO TempTable Select * from Attrib…

webstock php,workerman_connection

workerman_connection 测试WebStock 功能Description整理PHP 实现webstock 功能的相关流程。感谢workerman 开发作者提供开源组件。安装 composer# curl -sS https://getcomposer.org/installer | php如果安装 composer 提示PHP 版本不够按照如下处理&#xff0c;否则跳过。提示…

短信通信的几种情况和CMS错误

1&#xff0e; 如何与GSM MODEM建立通信联系 2&#xff0e; 不能与GSM MODEM进行正常的通信或总是在仿真终端上出现乱码 3&#xff0e; 如何才能知道错误代码 4&#xff0e; 发送短消息后&#xff0c;收到出错信息CMS ERROR 512 5&#xff0e; 发送短消息后&#xff0c;收到出错…