MVVM "A 'Binding' can only be set on a DependencyProperty of a DependencyObject."

MVVM "A 'Binding' can only be set on a DependencyProperty of a DependencyObject."

我有这个模型

[NotifyPropertyChanged]
public class WidgetConfiguration
{
    #region Properties
    #endregion Properties
}

我在我的 ViewModel 中将其用于集合和选定项 属性(ListView / GridView SelectedItem="{Binding SelectedWidget}" ...)

[NotifyPropertyChanged]
public class WidgetViewModel
{
    public ObservableCollection<WidgetConfiguration> Configurations { get; set; } = new ObservableCollection<WidgetConfiguration>();

    public WidgetConfiguration SelectedWidget { get; set; }
}

然后我想将 SelectedWidget 绑定到用作 SelectedItem 编辑器的 UserControl:

<controls:WidgetConfig Widget="{Binding SelectedWidget}" />

UserControl是这样定义的(使用PostSharp声明DependencyProperties)

[NotifyPropertyChanged]
public partial class WidgetConfig : UserControl
{
    [DependencyProperty]
    public WidgetConfiguration Widget { get; set; }

    public WidgetConfig()
    {
        InitializeComponent();

        this.DataContext = this;
    }
}

但是我在 UserControl 绑定上遇到错误:

Severity Code Description Project File Line Suppression State Error A 'Binding' cannot be set on the 'Widget' property of type 'Squiddy_Client_Views_WidgetConfig_10_577403948'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject. Client C:\develop\Squiddy\Client\Views\WidgetManager.xaml 21

我已经尝试手动实现 DependencyProperties 并确保所有类型都是正确的,甚至是默认类型和默认值。没用。

我已经阅读了 google 上的所有结果,但不知道该怎么做。

这是否可能,或者我是否需要进行代理绑定?

编辑:

为此,我尝试手动实现 DependencyProperty:

public static readonly DependencyProperty WidgetProperty = 
    DependencyProperty.Register("Widget", typeof(WidgetConfiguration),
    typeof(WidgetConfig));

[SafeForDependencyAnalysis]
public WidgetConfiguration Widget 
{
    get { return GetValue(WidgetProperty) as WidgetConfiguration; }
    set { SetValue(WidgetProperty, value); }
}

现在 XAML 错误消失了,但绑定已“失效”。在 ListView 中选择新对象时,UserControl 未更新:

编辑 2:

我完全错过了 PostSharp 文档中的这一部分,我没有添加 DependencyProperty 和属性。 (感谢 Daniel Balas)

public static DependencyProperty WidgetProperty { get; private set; }

[DependencyProperty]
public WidgetConfiguration Widget { get; set; }

编辑 3:

看完这个视频我终于找到了DataContext / root的答案: https://www.youtube.com/watch?v=h7ZrdGiOm3E

  1. 我从 UserControl 构造函数中删除了“this.DataContext = this”
  2. 我在 XAML
  3. 的 UserControl 元素中添加了一个 Name="root"
  4. UserControl 内的绑定应指向 ElementName=root 并使用 属性 Widget.xxx

像这样:

<UserControl Name="root">
  <TextBlock Text="{Binding Header, ElementName=root}"></TextBlock>
  <Label Content="{Binding Widget.Name, ElementName=root}" />
</UserControl>

Xaml/Baml 编译器通过查找 FooProperty 静态字段或 属性 来确定 属性 Foo 是否为依赖项 属性使用 DependencyProperty 类型。此字段不会由 [DependencyProperty] 方面自动注入(由于 PostSharp 的方面框架的限制)。

但是,当您声明此字段或 属性 时,Xaml 编译器足以将 属性 识别为依赖项 属性。 (然后方面将在运行时设置 field/property,因此它在运行时具有正确的值并且可用。)

public static DependencyProperty WidgetProperty { get; private set; }

[DependencyProperty]
public WidgetConfiguration Widget { get; set; }

您的 属性 setter 未被调用,因为 WPF 绑定更改了 DependencyObject 本身的值存储,而不是访问 属性 setter.

问题似乎在于您正在构造函数中更改控件的 DataContext。这将破坏在父控件中的 DataContext 上设置的绑定(绑定使用它们分配给的控件的 DataContext)。引用控件属性的一种方法如下:

<Label x:Name="label" Content="{Binding ElementName=root, Path=Widget.Name}" HorizontalAlignment="Left" />

其中“root”是 x:Name="root" 给您的控件(根 UserControl 元素)。