WPF中依賴屬性的值是是可以設置為可繼承(Inherits)的,這種模式下,父節點的依賴屬性會將其值傳遞給子節點。例如,數據綁定中經常使用的DataContextProperty:
var host = new ContentControl();
var button = new Button();
host.Content = button;
host.DataContext = Guid.NewGuid();
Contract.Assert(object.Equals(host.DataContext, button.DataContext));
可以看到,雖然沒有顯示給button的DataContext賦值,但其自然沿襲的父節點的值。
這個特性很大程度上省去了我們的不少代碼,那么如何使用自定義的依賴屬性也具有這一特性呢,網上找到的例子一般如下:
class Host : ContentControl
{
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(Host), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
}
class MyButton : Button
{
public object Value
{
get { return (object)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty = Host.ValueProperty.AddOwner(typeof(MyButton), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
}
可以看到,使能依賴屬性的基礎大體上要如下幾步:
-
使用 FrameworkPropertyMetadataOptions.Inherits使用 標記源屬性
-
使用 DependencyProperty.AddOwner注冊 衍生屬性,注冊時需要 FrameworkPropertyMetadataOptions.Inherits加上標記。
測試用例如下:
var host = new Host();
var button = new MyButton();
host.Content = button;
host.SetValue(Host.ValueProperty, Guid.NewGuid());
Contract.Assert(object.Equals(host.GetValue(Host.ValueProperty), button.GetValue(MyButton.ValueProperty)));
這種方式雖然沒有什么問題,但Host.ValueProperty.AddOwner(typeof(MyButton)這一截看起來非常別扭,研究了一下,實際上沒有這么嚴格的父子關系,這樣寫也是可以的:
class DependcyPropertyHelper
{
public static DependencyProperty RegistInherits<TOwner>(DependencyProperty property)
{
return property.AddOwner(typeof(TOwner), new FrameworkPropertyMetadata(property.DefaultMetadata.DefaultValue, FrameworkPropertyMetadataOptions.Inherits));
}
}
class DependencyData : DependencyObject
{
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(DependencyData));
}
class Host : ContentControl
{
public static readonly DependencyProperty ValueProperty = DependcyPropertyHelper.RegistInherits<Host>(DependencyData.ValueProperty);
}
class MyButton : Button
{
public static readonly DependencyProperty ValueProperty = DependcyPropertyHelper.RegistInherits<MyButton>(DependencyData.ValueProperty);
}
這樣寫看起來就舒服一些了。細心的朋友看下就能發現:源屬性DependencyData.ValueProperty都沒有標記為可繼承的(第一種方式下非要標記為可繼承的),找了一下,也沒有發現官方的詳細文檔的說明這個規則到底是什么樣的,有空發現后再補充。