摘要:上面在說明附加屬性綁定的時候我特地額外寫了一個不需要寫命名空間的 XAML 綁定附加屬性的代碼,這是爲了說明接下來寫 C# 代碼時的注意事項。本文將介紹如何在 XAML 和 C# 代碼中綁定附加屬性。

在 XAML 中寫綁定是 WPF 學習的必修課,進階一點的,是用 C# 代碼來寫綁定。然而一旦綁定的屬性是附加屬性,好多小夥伴就會開始遇到坑了。

本文將介紹如何在 XAML 和 C# 代碼中綁定附加屬性。

背景代碼

開始遇到這個問題的背景是我定義了一個附加屬性,然後試圖通過綁定的方式完成一些業務。

用附加屬性來完成的很大一個好處在於不需要改動原有的代碼破壞原來的類。例如我只需要在任何一個類中定義 IsDraggable 附加屬性,就可以讓我其他地方的 Grid Button 等支持拖拽。

public class DraggableElement : FrameworkElement
{
    static TabViewItem()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(DraggableElement),
            new FrameworkPropertyMetadata(typeof(DraggableElement)));
    }

    public static readonly DependencyProperty IsDraggableProperty =
        DependencyProperty.RegisterAttached(
            "IsDraggable", typeof(bool), typeof(TabViewItem),
            new PropertyMetadata(true));

    public static bool GetIsDraggable(DependencyObject item)
        => (bool) item.GetValue(IsDraggableProperty);

    public static void SetIsDraggable(DependencyObject obj, bool value)
        => obj.SetValue(IsDraggableProperty, value);
}

在 XAML 中綁定附加屬性

在 XAML 中綁定附加屬性的時候需要加上括號和類型的命名空間前綴:

<ListViewItem Content="{Binding (local:DraggableElement.IsDraggable), RelativeSource={RelativeSource Self}}"
              local:DraggableElement.IsDraggable="True" />

對於 WPF 內置的命名空間( http://schemas.microsoft.com/winfx/2006/xaml/presentation 命名空間下),是不需要加前綴的。

<TextBlock x:Name="DemoTextBlock" Grid.Row="1"
           Text="{Binding (Grid.Row), RelativeSource={RelativeSource Self}}" />

跟其他的綁定一樣,這裏並不需要在 Binding 後面寫 Path= ,因爲 Binding 的構造函數中傳入的參數就是賦值給 Path 的。

在 C# 代碼中綁定附加屬性

上面在說明附加屬性綁定的時候我特地額外寫了一個不需要寫命名空間的 XAML 綁定附加屬性的代碼,這是爲了說明接下來寫 C# 代碼時的注意事項。

是這樣寫嗎?

// 給不看全文的小夥伴:這段代碼是無法工作的!正常工作的在後文。
Binding binding = new Binding("(Grid.Row)")
{
    Source = DemoTextBlock,
}
BindingOperations.SetBinding(DemoTextBlock, TextBox.TextProperty, binding);

設想應該不是,因爲 C# 代碼中是沒有命名空間前綴的,於是對於前面 XAML 中 (local:DraggableElement.IsDraggable)local 部分就很不好處理。

實際上,這裏的字符串即便是寫成 System.Windows.Grid.RowWalterlv.BindingDemo.DraggableElement.IsDraggable 也依然會綁定失敗。

在 C# 代碼中綁定附加屬性,需要 使用依賴項屬性,而不能使用字符串

Binding binding = new Binding
{
    Source = DemoTextBlock,
    Path = new PropertyPath(Grid.RowProperty),
}
BindingOperations.SetBinding(DemoTextBlock, TextBox.TextProperty, binding);
Binding binding = new Binding
{
    Source = DemoDraggableElement,
    Path = new PropertyPath(DraggableElement.IsDraggableProperty),
}
BindingOperations.SetBinding(DemoDraggableElement, TextBox.TextProperty, binding);

因此需要特別注意,附加屬性的綁定不再能使用字符串,需要使用依賴項屬性。

參考資料

相關文章