【问题标题】:MVVM "A 'Binding' can only be set on a DependencyProperty of a DependencyObject."MVVM“只能在 DependencyObject 的 DependencyProperty 上设置‘绑定’。”
【发布时间】:2021-07-16 09:47:24
【问题描述】:

我有这个模型

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

我在 ViewModel 中将其用于 Collection 和 Selected 项目属性(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 绑定上遇到错误:

严重性代码描述项目文件行抑制状态错误A 无法在类型的“小部件”属性上设置“绑定” 'Squiddy_Client_Views_WidgetConfig_10_577403948'。 “绑定”只能 在 DependencyProperty 上设置 依赖对象。客户端 C:\develop\Squiddy\Client\Views\WidgetManager.xaml 21

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

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

这是可能的还是我需要进行代理绑定?

编辑:

只是为了它,我尝试手动实现 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 不会更新:

  • PropertySetter 没有被调用
  • ViewModel 上的 PropertyChanged 事件确实会发生...

编辑 2:

我完全错过了 PostSharp 文档中的这一部分,我没有添加 DependencyProperty 以及属性。 (感谢丹尼尔·巴拉斯)

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 的 UserControl 元素中添加了一个 Name="root"
  3. UserControl 内的绑定应指向 ElementName=root 并使用属性 Widget.xxx

像这样:

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

【问题讨论】:

    标签: mvvm dependency-properties inotifypropertychanged postsharp


    【解决方案1】:

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

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

    public static DependencyProperty WidgetProperty { get; private set; }
    
    [DependencyProperty]
    public WidgetConfiguration Widget { get; set; }
    

    不会调用您的属性设置器,因为 WPF 绑定会更改 DependencyObject 本身上的值存储,而不是访问属性设置器。

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

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

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

    【讨论】:

    • 我一定错过了添加静态 DependencyProperty 的部分,这样做之后我的错误更少。我不明白关于 DataContext 的事情。我不应该在 UserControl 中设置 DataContext 还是应该默认发生?我已经尝试过你的建议,但它不起作用:(
    • 关于 DataContext 和 ElementName 我想通了
    猜你喜欢
    • 2012-07-11
    • 1970-01-01
    • 2017-10-30
    • 1970-01-01
    • 2012-04-19
    • 2019-05-02
    • 2011-03-18
    • 2011-01-17
    • 2018-02-09
    相关资源
    最近更新 更多