WPF绑定报错:BindingExpression生成的值对目标属性无效
错误信息
Value produced by BindingExpression is not valid for target property.
MenuItem:'WpfApp1.Models.MenuItem' BindingExpression:Path=SelectedMenuItem;
DataItem='MainViewModel' (HashCode=29578451); target element is 'Menu' (Name=''); target
property is 'SelectedItem' (type 'MenuItem')
核心触发原因
1. 依赖属性回调的循环赋值逻辑错误
在Menu控件的SelectedItemProperty变更回调OnSelectedItemChanged中,存在致命的循环赋值问题:
public static void OnSelectedItemChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs) { var menu = dependencyObject as Menu; if (menu == null) { return; } menu.SetCurrentValue(SelectedItemProperty, eventArgs.NewValue); }
当ViewModel的SelectedMenuItem通过双向绑定更新Menu的SelectedItem属性时,会触发该回调;但回调里又调用SetCurrentValue重新设置同一个依赖属性,这会引发绑定循环:控件属性变更通知ViewModel更新,ViewModel更新再次触发控件属性变更,循环往复导致绑定系统状态异常,最终抛出类型匹配但逻辑无效的错误。
2. Menu控件内部ItemsSource绑定指向错误
Menu.xaml中ItemsControl的ItemsSource绑定直接指向了DataContext的MenuItems:
<ItemsControl d:DataContext="{Binding Source={StaticResource DesignViewModel}}" ItemsSource="{Binding Path=MenuItems, Mode=OneWay}">
但Menu控件自身已定义Items依赖属性,且在Window.xaml中已将ViewModel的MenuItems绑定到该属性。错误的绑定指向会导致数据来源混乱,间接加剧绑定系统的异常逻辑。正确的绑定应指向控件自身的Items属性:
ItemsSource="{Binding Path=Items, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=OneWay}"
3. 冗余的INotifyPropertyChanged实现
Menu控件作为依赖对象,其依赖属性本身会自动触发变更通知,无需额外实现INotifyPropertyChanged接口,这部分冗余代码虽不直接引发错误,但会增加代码复杂度。
修复方案
- 删除循环赋值代码:移除
OnSelectedItemChanged中的menu.SetCurrentValue(SelectedItemProperty, eventArgs.NewValue);,回调仅处理必要业务逻辑,无需重新设置自身依赖属性。 - 修正ItemsSource绑定:将
Menu.xaml中ItemsControl的ItemsSource绑定指向控件自身的Items属性。 - 移除冗余代码:删除
Menu控件中的INotifyPropertyChanged接口实现及相关事件代码。
内容的提问来源于stack exchange,提问作者Józef Podlecki

