昨天在网上看到一个网友问如何在WPF里面实现相互依赖的属性,例如下面一个类:
using System;
public class RtdField
{
#region SizeX
public Double X1
{
get { return x1; }
set
{
x1 = value;
OnPropertyChanged("X1");
OnPropertyChanged("X");
OnPropertyChanged("OffsetX");
}
}
private Double x1;
public Double X2
get { return x2; }
x2 = value;
OnPropertyChanged("X2");
private Double x2;
public double X
get { return x1 + x2; }
double hx = value / 2.0;
double ox = OffsetX;
x1 = hx - ox;
x2 = hx + ox;
OnPropertyChanged("X1");
public double OffsetX
get { return (x2 - x1) / 2.0; }
set
double hx = X / 2.0;
double ox = value;
#endregion
}
需要实现,如果OffsetX发生了变化, 那么X1和X2跟着发生变化,然而X1或者X2发生变化,那么X和OffsetX的值也发生变化。
我第一个想到的方法就是使用WPF的数据绑定,使用多重绑定(MultiBinding)和对应的转换器(Converter)来做,因为数据绑定支持双向绑定(Mode.TwoWay),即一个属性变化了,依赖它的其他属性都跟着变化,而依赖属性变化了,原先的属性也会跟着发生变化。
使用数据绑定的方法,其实就是将OffsetX和X属性绑定到X1和X2上面,数据源是对象自己,然后把X和OffsetX里面的Set函数移到对应的值转换器(ValueConverter)里面就好了。
代码:
public partial class Window1 : Window
public Window1()
InitializeComponent();
TestClass tc = new TestClass();
tc.X1 = 1;
tc.X = 2.4;
public class TestClass : DependencyObject
public double X1
get { return (double)GetValue(X1Property); }
set { SetValue(X1Property, value); }
public static readonly DependencyProperty X1Property =
DependencyProperty.Register("X1", typeof(double), typeof(TestClass), newUIPropertyMetadata(0.0));
public double X2
get { return (double)GetValue(X2Property); }
set { SetValue(X2Property, value); }
public static readonly DependencyProperty X2Property =
DependencyProperty.Register("X2", typeof(double), typeof(TestClass), newUIPropertyMetadata(0.0));
get { return (double)GetValue(XProperty); }
set { SetValue(XProperty, value); }
public static readonly DependencyProperty XProperty =
DependencyProperty.Register("X", typeof(double), typeof(TestClass), newUIPropertyMetadata(0.0));
get { return (double)GetValue(OffsetXProperty); }
set { SetValue(OffsetXProperty, value); }
public static readonly DependencyProperty OffsetXProperty =
DependencyProperty.Register("OffsetX", typeof(double), typeof(TestClass), newUIPropertyMetadata(0.0));
public TestClass()
MultiBinding binding = new MultiBinding();
binding.Bindings.Add(new Binding("X1")
RelativeSource = RelativeSource.Self,
// 下面这个模式一定要设置,否则
// X属性更改了,虽然会调用X1X2ToXConverter.ConvertBack
// 函数,但是生成的值不会放回到X1和X2里面。
Mode = BindingMode.TwoWay
});
binding.Bindings.Add(new Binding("X2")
Mode = BindingMode.TwoWay
binding.Converter = new X1X2ToXConverter();
// 下面这个模式也要设置,否则X属性更改不会
// 让WPF自动调用X1X2ToXConverter.ConvertBack函数
binding.Mode = BindingMode.TwoWay;
binding.ConverterParameter = this;
BindingOperations.SetBinding(this, XProperty, binding);
binding = new MultiBinding();
Mode = BindingMode.TwoWay
binding.Converter = new X1X2ToOffsetXConverter();
BindingOperations.SetBinding(this, OffsetXProperty, binding);
public class X1X2ToXConverter : IMultiValueConverter
#region IMultiValueConverter Members
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
return (double)values[0] + (double)values[1];
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
double hx = (double)value / 2.0;
var tc = parameter as TestClass;
double ox = tc.OffsetX;
var result = new object[] {
hx - ox,
hx + ox};
return result;
public class X1X2ToOffsetXConverter : IMultiValueConverter
return ((double)values[1] - (double)values[0]) / 2.0;
double hx = ((TestClass)value).X / 2.0;
double ox = (double)value;
本文转自 donjuan 博客园博客,原文链接: http://www.cnblogs.com/killmyday/archive/2009/09/18/1569569.html ,如需转载请自行联系原作者