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 未更新:
- 未调用 PropertySetter
- ViewModel 上的 PropertyChanged 事件确实发生了...
编辑 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
- 我从 UserControl 构造函数中删除了“this.DataContext = this”
- 我在 XAML
的 UserControl 元素中添加了一个 Name="root"
- 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 元素)。
我有这个模型
[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 未更新:
- 未调用 PropertySetter
- ViewModel 上的 PropertyChanged 事件确实发生了...
编辑 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
- 我从 UserControl 构造函数中删除了“this.DataContext = this”
- 我在 XAML 的 UserControl 元素中添加了一个 Name="root"
- 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 元素)。