/// <summary> /// 目标属性发生变化时的处理事件方法。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void MyDependencyObject_PropertyChanged(object sender, PropertyChangedEventArgs e) { MyDependencyProperty p = null; //找到绑定属性所在的依赖属性 foreach (var b in _bindings) { if (b.Value.PropertyName == e.PropertyName) { p = b.Key; break; } } //不为空则处理. if (p != null) { System.Reflection.PropertyInfo thePI = sender.GetType().GetProperty(e.PropertyName); if (thePI != null && thePI.CanRead == true) { object theVal = thePI.GetValue(sender, null); SetValue(p, theVal); //如果目标类INotifyPropertyChanged,绑定模式是ontime,则下面的代码就是要接触与目标属性的挂接. if (sender is INotifyPropertyChanged) { ((INotifyPropertyChanged)sender).PropertyChanged += new PropertyChangedEventHandler(MyDependencyObject_PropertyChanged); } } } }
/// <summary> /// 设置绑定属性,一样是模拟微软的干活,只不过微软的这个方法不是在依赖对象里实现的, /// 而是在UIElement里实现的. /// </summary> /// <param name="p"></param> /// <param name="Binding"></param> public void SetBinding(MyDependencyProperty p, MyBinding Binding) { MyBinding theOld = null; //需要先将老的绑定找到并记录,因为需要解除挂接. if (_bindings.ContainsKey(p)) { theOld = _bindings[p]; _bindings[p] = Binding; } else { _bindings.Add(p, Binding); } //删除旧的绑定. if (theOld != null) { if (theOld.TargetObject is INotifyPropertyChanged) { ((INotifyPropertyChanged)theOld.TargetObject).PropertyChanged -= new PropertyChangedEventHandler(MyDependencyObject_PropertyChanged); } } //如果是单向绑定或者双向绑定则需要以下挂接。如果只是Onetime则不必要. if (Binding.TargetObject is INotifyPropertyChanged) { ((INotifyPropertyChanged)Binding.TargetObject).PropertyChanged += new PropertyChangedEventHandler(MyDependencyObject_PropertyChanged); } }
//依赖属性实例化工厂方法类. public static MyDependencyProperty Register(string name, Type propertyType, Type ownerType, MyPropertyMetadata propertyMetadata) { if (propertyMetadata != null && propertyMetadata.DefaultValue.GetType() != propertyType) { throw new Exception(string.Format("the type of defaultValue is not {0}", propertyType.Name)); } MyDependencyProperty dp = new MyDependencyProperty(name, propertyType, ownerType, propertyMetadata); return(dp); }
public object GetValue(MyDependencyProperty p) { //如果被动画控制,返回动画计算值。(可能会用到p.Name) //如果有本地值,返回本地值 if (_dict.ContainsKey(p)) { return(_dict[p]); } //如果有Style,则返回Style的值 //返回从可视化树中继承的值 //最后, 返回依赖属性的DefaultValue return(p.DefaultValue); }
public static MyDependencyProperty Register(string name, Type propertyType, Type ownerType) { MyDependencyProperty dp = new MyDependencyProperty(name, propertyType, ownerType, new MyPropertyMetadata()); return(dp); }
public void SetValue(MyDependencyProperty p, object val) { //如果设置值是默认值,则可不保存,以节省空间. object theOldValue = null; if (_dict.ContainsKey(p)) { theOldValue = _dict[p]; //如果已有设置值,且等于当前设置值,则退出 if (theOldValue == val) { return; } //如果设置值等于默认值,则删除已有的设置值。 if (p.DefaultValue == val) { _dict.Remove(p); return; } //设置新的字典值 _dict[p] = val; } else { //如果设置值不等于默认值,则增加设置值,否则不做任何设置。 if (p.DefaultValue != val) { _dict.Add(p, val); } else { return; } } if (p.PropertyMetadata != null && p.PropertyMetadata.PropertyChangedCallback != null) { MyDependencyPropertyChangedEventArgs theArgs = new MyDependencyPropertyChangedEventArgs(val, theOldValue, p); p.PropertyMetadata.PropertyChangedCallback(this, theArgs); } //如果是双向绑定,则需要同步数据到绑定数据源,这里假设需要双向绑定. if (_bindings.ContainsKey(p) == true) { MyBinding theBinding = _bindings[p]; if (theBinding.TargetObject != null && theBinding.PropertyName != "") { System.Reflection.PropertyInfo thePI = theBinding.TargetObject.GetType().GetProperty(theBinding.PropertyName); if (thePI != null && thePI.CanWrite == true) { //对于有索引的设置值比较复杂一点,可利用反射来进行,这里只是演示简单属性。 //注意,如果目标类实现了INotifyPropertyChanged接口,并有修改触发机制,那么这里的设置 //会触发目标属性改变事件,就会触发MyDependencyObject_PropertyChanged执行, //而MyDependencyObject_PropertyChanged里又调用了SetValue函数,这就会死循环,这也是 //为什么前面的代码中为什么要判断如果已经有的设置值等于当前设置新值直接退出的缘故,就是 //为了阻止死循环.当然,在目标属性中set里面做判断也可以,但这里一定要做, //原因大家可以自己想一下。 thePI.SetValue(theBinding.TargetObject, val, null); OnEvent(); } } } }
public MyDependencyPropertyChangedEventArgs(object NewValue, object OldValue, MyDependencyProperty Property) { this.NewValue = NewValue; this.OldValue = OldValue; this.Property = Property; }