嵌套UserControl通信问题:ListView选中项同步至详情控件异常
我来帮你搞定这个嵌套UserControl的通信问题,咱们一步步梳理错误点和解决方案:
首先,你遇到的XAML解析错误是最直接的问题:
System.Windows.Markup.XamlParseException: ''Provide value on 'System.Windows.Data.Binding' threw an exception.' Line number '26' and line position '17'.'
内部异常:InvalidOperationException: Two-way binding requires Path or XPath.
这个错误是因为你写的SelectedItem="{Binding Mode=TwoWay}"没有指定绑定的属性路径,而且更关键的是,你需要明确绑定到UserControl自身的依赖属性,而非默认DataContext。除此之外,你的代码还有几个容易忽略的问题,下面逐一修正:
1. 修正依赖属性的命名错误
WPF依赖属性有严格的命名约定:属性名+Property,你的SelectedEmployee属性对应的依赖属性字段名写错了(写成了EmployeeProperty),这会导致WPF绑定系统无法正确识别该属性,直接引发绑定失效。
修正后的后台代码:
//Selected Item public Employee SelectedEmployee { get { return (Employee)GetValue(SelectedEmployeeProperty); } set { SetValue(SelectedEmployeeProperty, value); NotifyPropertyChanged(); } } public static readonly DependencyProperty SelectedEmployeeProperty = DependencyProperty.Register( nameof(SelectedEmployee), typeof(Employee), typeof(UserControlEmployees), new PropertyMetadata(default, SetNewSelected));
2. 移除XAML中的嵌套ListView错误
你的XAML里意外嵌套了两层<ListView>标签,这会导致布局混乱和绑定异常,直接删除外层的ListView即可:
<!-- ListView --> <ListView x:Name="ControlEmployeesListView" Grid.Row="0"> <ListView.ItemTemplate> <DataTemplate> <uc:UserControlEmployeeListItem EmployeeListItem="{Binding}" /> </DataTemplate> </ListView.ItemTemplate> </ListView>
3. 正确绑定ListView的SelectedItem到UserControl的依赖属性
要实现ListView选中项与SelectedEmployee的双向绑定,需要明确指定绑定源为UserControl自身,用RelativeSource实现:
<ListView x:Name="ControlEmployeesListView" Grid.Row="0" ItemsSource="{Binding Employees, RelativeSource={RelativeSource AncestorType=UserControl}}" SelectedItem="{Binding SelectedEmployee, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay}">
这里顺便把ItemsSource也改成XAML绑定,代替后台代码的手动赋值,更符合MVVM规范,你可以删掉SetNew回调里的control.ControlEmployeesListView.ItemsSource = e.NewValue as ObservableCollection<Employee>;代码。
4. 绑定详情控件到SelectedEmployee
同样,把UserControlEmployeeDetails的EmployeeDetail属性绑定到UserControl的SelectedEmployee:
<!-- Details --> <uc:UserControlEmployeeDetails Grid.Row="1" EmployeeDetail="{Binding SelectedEmployee, RelativeSource={RelativeSource AncestorType=UserControl}, Mode=TwoWay}" />
5. 清理后台冗余逻辑
因为绑定已经自动处理了选中项和详情控件的赋值,所以可以删掉SetNewSelected回调里的手动赋值代码,避免和绑定逻辑冲突:
private static void SetNewSelected(DependencyObject d, DependencyPropertyChangedEventArgs e) { var control = d as UserControlEmployees; if (control != null) { // 移除以下两行冗余代码 // control.ControlUserControlEmployeeDetails.EmployeeDetail = e.NewValue as Employee; // control.ControlEmployeesListView.SelectedItem = e.NewValue as Employee; } }
6. 确保外部ViewModel的绑定正确
在主窗口ViewMain中使用UserControlEmployees时,要正确绑定到ViewModel的对应属性:
<uc:UserControlEmployees Employees="{Binding YourViewModelEmployeesCollection}" SelectedEmployee="{Binding YourViewModelSelectedEmployee, Mode=TwoWay}" />
经过这些修正,你的嵌套UserControl就能实现预期的功能:ListView选中项与SelectedEmployee双向同步,详情控件实时展示并编辑选中的员工数据。
内容的提问来源于stack exchange,提问作者user6715722

