Prism WPF动态加载UserControl并向其ViewModel设置MachineId属性求助
问题根因
你手动添加MachineDashboard时,控件的DataContext是Prism默认注入的独立MachineDashboardViewModel实例,因此Style中绑定的MachineId可以正确找到VM中的对应属性。当控件放到ItemsControl的DataTemplate中时,每个控件的默认DataContext会被替换为Machines集合的元素对象,你写在Style中的绑定找不到正确的VM属性,哪怕写死依赖属性值,也会被双向绑定的失效结果覆盖,导致值无法传递到VM。
推荐解决方案(适配Prism DI规范)
步骤1:在父ViewModel中预创建带MachineId的子VM集合
由于你的MachineDashboardViewModel需要依赖注入,不要直接手动实例化,通过Prism的IContainerProvider创建实例,从数据库读取到设备ID后直接赋值给对应VM:
public class HomeViewModel : BindableBase { private readonly IContainerProvider _containerProvider; public ObservableCollection<MachineDashboardViewModel> Machines { get; } = new(); // 注入容器提供器 public HomeViewModel(IContainerProvider containerProvider) { _containerProvider = containerProvider; LoadMachinesFromDb(); } private void LoadMachinesFromDb() { // 替换为实际从数据库读取设备ID的逻辑 List<int> dbMachineIds = new List<int> { 1, 2, 3 }; foreach (var machineId in dbMachineIds) { // 容器自动注入IDialogService、ILogger等依赖 var machineVm = _containerProvider.Resolve<MachineDashboardViewModel>(); machineVm.MachineId = machineId; Machines.Add(machineVm); } } }
步骤2:简化XAML绑定,移除无效依赖属性绑定
你可以直接废弃原来的MachineId_DP依赖属性和对应的Style绑定,ItemsControl直接绑定预创建的VM集合即可:
<ItemsControl Grid.Row="1" ItemsSource="{Binding Machines}"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <WrapPanel /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <!-- 直接把DataContext绑定为预创建的VM实例 --> <local:MachineDashboard DataContext="{Binding}" Margin="10"/> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
可选方案:保留依赖属性的兼容实现
如果你需要保留MachineDashboard的MachineId_DP依赖属性做封装,只需要给依赖属性添加属性变更回调,直接给控件自身的VM赋值,规避DataContext变化带来的绑定失效问题:
// MachineDashboard.xaml.cs 后台代码 public static readonly DependencyProperty MachineId_DPProperty = DependencyProperty.Register( "MachineId_DP", typeof(int), typeof(MachineDashboard), new PropertyMetadata(default(int), OnMachineIdChanged)); private static void OnMachineIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is not MachineDashboard control) return; if (control.DataContext is MachineDashboardViewModel vm) { vm.MachineId = (int)e.NewValue; control._pendingMachineId = null; return; } // VM未初始化时暂存值,等待DataContext赋值 control._pendingMachineId = (int)e.NewValue; } private int? _pendingMachineId; public MachineDashboard() { InitializeComponent(); // 监听DataContext变化,赋值暂存的MachineId DataContextChanged += (s, e) => { if (e.NewValue is MachineDashboardViewModel vm && _pendingMachineId.HasValue) { vm.MachineId = _pendingMachineId.Value; _pendingMachineId = null; } }; }
此时你可以直接沿用原来的动态绑定写法,不需要修改ItemsControl的XAML。
内容的提问来源于stack exchange,提问作者Dejan Batljan
相关产品推荐
相关产品推荐

