WPF:DependencyProperty适用于TextBlock,但不适用于自定义控件

时间:2017-10-02 10:54:46

标签: c# wpf xaml dependency-properties

修改:可以找到示例项目here

我在主窗口中使用了ListBox,我稍后将其绑定到ObservableCollection。我同时使用TextBlock和自定义控件,它绑定到集合的同一属性。我的问题是TextBlock得到了正确的更新,而自定义控件却没有(它得到默认构造,但它的Text属性永远不会被绑定更新。)

<ListBox Name="MyCustomItemList">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding ItemText}"/>
                <local:MyCustomBlock Text="{Binding ItemText}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

我将MyCustomBlock作为System.Windows.Controls.Canvas的子项实现,并具有Text依赖项属性:

public class MyCustomBlock : Canvas
{
    public MyCustomBlock() => Text = "<default>";
    public MyCustomBlock(string text) => Text = text;

    private static void TextChangedCallback(DependencyObject o,
                                            DependencyPropertyChangedEventArgs e)
    {
        ...
    }

    public string Text
    {
        get => (string)GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }

    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register(
              nameof(Text), typeof(string), typeof(MyCustomBlock),
              new FrameworkPropertyMetadata("", TextChangedCallback));
}

最后,这是我绑定到ListBox构造函数中MainWindow的数据:

public class MyCustomItem
{
    public MyCustomItem(string text) => ItemText = text;
    public string ItemText { get; set; }
}

public MainWindow()
{
    InitializeComponent();

    var list = new ObservableCollection<MyCustomItem>();
    list.Add(new MyCustomItem("Hello"));
    list.Add(new MyCustomItem("World"));
    MyCustomItemList.ItemsSource = list;
}

我在设置中忘记了什么吗?为什么TextBlock.Text似乎已正确更新但未MyCustomBlock.Text

1 个答案:

答案 0 :(得分:3)

依赖项属性可以从多个来源获取其值,因此WPF使用precedence系统来确定应用哪个值。 “本地”值(使用SetValueSetBinding提供)将覆盖创建模板提供的任何内容。

在您的情况下,您在构造函数中设置“本地”值(可能意味着它表现为默认值)。设置默认值的更好方法是在PropertyMetadata中提供它。

public static readonly DependencyProperty TextProperty =
    DependencyProperty.Register(
          nameof(Text), typeof(string), typeof(MyCustomBlock),
          new FrameworkPropertyMetadata("<default>", TextChangedCallback));