只能在 DependencyObject 的 DependencyProperty 上设置“绑定”

Posted

技术标签:

【中文标题】只能在 DependencyObject 的 DependencyProperty 上设置“绑定”【英文标题】:A 'Binding' can only be set on a DependencyProperty of a DependencyObject 【发布时间】:2012-07-11 06:08:11 【问题描述】:

从一个基于TextBox的自定义控件,我创建了一个名为Items的属性,这样:

public class NewTextBox : TextBox

    public ItemCollection Items  get; set; 

在 XAML 中使用自定义控件时,我无法绑定该属性,因为它会引发异常“A 'Binding' can only be set on a DependencyProperty of a DependencyObject。”。

如何解决这个异常?

【问题讨论】:

是的。只有依赖属性可以作为绑定的目标。 Source 可以是依赖属性或实现 INotifyPropertyChanged 的​​ CLR 属性 这与您的其他问题完全相同,您接受答案并说“但我必须修改属性以包含 DependencyProperty”。您的解决方案应该作为答案包含在其中 @AdamHouldsworth 是的,发布这个问题只是为了发布答案。这实际上是被鼓励的,因为它被视为一种分享知识的形式,甚至还有一个new CheckBox on the form 可以让您在写问题的同时写一个答案。 @Rachel 很公平,我没有发现这一点,因为我已经很长时间没有提出问题了。无论哪种方式,我都没有否决这个问题或答案,所以我的手很干净:-) @arserbin3 Rachel 有正确的解释。我选择在这里发布而不是旧问题,因为我认为绑定问题与 DependencyProperty 异常不同。 【参考方案1】:

另外值得注意的是,如果您在对象之间复制和粘贴而忘记更改第二个 typeof(Object) 语句,则会收到这些绑定错误。

一小时后我都想不通为什么会出现这个错误,因为一切似乎都已定义且正确。当我想从一个集合变成一个列表时,我将我的属性移动到了一个用户控件中。因此:

public static readonly DependencyProperty FoldersProperty = DependencyProperty
    .Register("Folders", typeof(OutlookFolders), typeof(MainWindow),
    new FrameworkPropertyMetadata(new OutlookFolders()));

public OutlookFolders Folders

    get  return GetValue(FoldersProperty) as OutlookFolders; 
    set  SetValue(FoldersProperty, value); 

应该变成:

public static readonly DependencyProperty FoldersProperty = DependencyProperty
    .Register("Folders", typeof(OutlookFolders), typeof(SavedFolderControl), 
    new FrameworkPropertyMetadata(new OutlookFolders()));

public OutlookFolders Folders

    get  return GetValue(FoldersProperty) as OutlookFolders; 
    set  SetValue(FoldersProperty, value); 

在我进行此更改之前,我一直收到错误消息: A 'Binding' cannot be set on the property 'Folders' of type 'SavedFolderControl'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.

【讨论】:

这个。我复制了一个带有一些 DependencyProperties 的 UserControl,这意味着旧的 typeof(____)-Value 仍然存在并且有效。直到运行时我才收到任何错误。然后是 XAML Parsing Exception "A Binding can only be set..." 等等。谢谢! 它可能存在,但建议的类型实际匹配的类型。 不,这就是重点。我的意思是这个类存在并且是有效的。所以你不会在VS中得到任何错误。直到你编译并运行。但是你不知道错误来自哪里!那是我复制后的错误.. 啊,是的。我也是这样做的。只有当我读到有关复制和粘贴的内容以彻底检查它时才在我的脑海中敲响,因为这就是我所做的。 谢谢,我想你刚刚为我节省了大约一个小时!【参考方案2】:

要解决此异常,您需要更改属性Items 并添加一个DependencyProperty,它将在XAML 中用作“链接”。课程将是:

public class AutocompleteTextBox : TextBox

    public ItemCollection Items
    
        get 
            return (ItemCollection)GetValue(ItemsProperty); 
        set 
            SetValue(ItemsProperty, value); 
    

    public static readonly DependencyProperty ItemsProperty =
        DependencyProperty.Register(
            "Items",
            typeof(ItemCollection),
            typeof(AutocompleteTextBox),
            new PropertyMetadata(default(ItemCollection), OnItemsPropertyChanged));

    private static void OnItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    
        // AutocompleteTextBox source = d as AutocompleteTextBox;
        // Do something...
    

【讨论】:

【参考方案3】:

这里还有一个问题:确保DependencyProperty.Register() 的第一个参数中的字符串与相关属性的名称匹配。

public static readonly DependencyProperty ItemsProperty =
    DependencyProperty.Register(
        "TheItems", // This is wrong
        typeof(ItemCollection),
        typeof(AutocompleteTextBox),
        new PropertyMetadata(default(ItemCollection), OnItemsPropertyChanged));

我在不更改字符串的情况下重命名属性时遇到了这个问题。

【讨论】:

确保名称是“Items”,而不是“ItemsProperty” 您可以在最近的 .NET 版本中使用 nameof(Items) 来避免这个问题。【参考方案4】:

我注意到但我不确定是否在任何地方提到的一件事是,您的 DependencyProperty 的名称必须匹配您的属性名称

如果您的属性名称是Items,那么您DependencyProperty 必须ItemsProperty

在我的情况下,一旦我匹配它们,错误就消失了

【讨论】:

哇。我不敢相信这解决了警告。完全没有意义,但有效。尽管我的绑定在运行时确实有效,但我一直看到这个警告,直到我将 DependencyProperty 变量名更改为附加了 Property【参考方案5】:

另一个可能的原因是您为元数据中的默认值提供了错误的类型。 例如:

new PropertyMetadata(default(ItemCollection), OnItemsPropertyChanged)

如果你改写会抛出这个错误:

new PropertyMetadata(false, OnItemsPropertyChanged)

如果您从代码源复制和粘贴,也会发生这种情况。

【讨论】:

【参考方案6】:

我收到了(运行时 + 设计时)消息:

未处理的类型异常 'System.Windows.Markup.XamlParseException' 发生在 PresentationFramework.dll

附加信息:不能在“属性”上设置“绑定” “触发器”类型的属性。 “绑定”只能设置在 DependencyObject 的 DependencyProperty。

我足够聪明,可以在 VM 属性上定义触发器。

// incorrect.. cannot have Trigger for VM property
<Trigger Property="Binding IsExpanded" Value="True">
  <Setter Property="Visibility" Value="Visible"/>
</Trigger>

当然应该是数据触发器(使用绑定而不是属性)

<DataTrigger Binding="Binding IsExpanded" Value="True">
  <Setter Property="Visibility" Value="Visible"/>
</DataTrigger>

触发器通常用于控件(按钮、文本框、框架元素等)属性。

【讨论】:

【参考方案7】:

由于我缺乏监督,我遇到了这个问题。我写了

<Button.Visibility>
   <MultiBinding Converter="StaticResource mvbConverter">
     <Binding Path="Binding isActive" />
     <Binding Path="Binding isCashTransaction" />
   </MultiBinding>
</Button.Visibility>

什么时候我应该写

<Button.Visibility>
   <MultiBinding Converter="StaticResource mvbConverter">
     <Binding Path="isActive" />
     <Binding Path="isCashTransaction" />
   </MultiBinding>
</Button.Visibility>

【讨论】:

以上是关于只能在 DependencyObject 的 DependencyProperty 上设置“绑定”的主要内容,如果未能解决你的问题,请参考以下文章

WPF - 转换器作为 DependencyObject

ViewModel应该继承WPF中的DependencyObject吗?

必须在与 DependencyObject 相同的线程上创建 DependencySource

WPF编程宝典之依赖项属性

在模块 WindowsBase.dll 中找不到类型 System.Windows.DependencyObject

UWP DependencyObject 绑定 Windows.UI.Xaml.Markup.XamlParseException