MVVM模式下同一View中按钮绑定不同ViewModel命令的可行性咨询
当然可以实现!
你完全能在同一个View里让不同按钮分别绑定到两个ViewModel的命令,不过从你贴的代码来看,有几个小问题需要调整,咱们一步步来解决:
1. 先修正ViewModel的构造函数错误
你写的FirstViewModel和SecondViewModel的构造函数名称都是HomeViewModel(),这明显是笔误!构造函数名称必须和类名一致,不然命令根本不会被初始化,这是最关键的坑:
// 修正FirstViewModel的构造函数 public class FirstViewModel : INotifyPropertyChanged { public MyICommand<string> FirstCommand { get; private set; } // 构造函数名要和类名一致 public FirstViewModel() { FirstCommand = new MyICommand<string>(myFirstCommand); } public void myFirstCommand(string par) { Console.Beep(); } // 别忘了实现INotifyPropertyChanged的必要成员(你应该已经写了,这里补全示意) public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } // 同理修正SecondViewModel的构造函数 public class SecondViewModel : INotifyPropertyChanged { public MyICommand<string> SecondCommand { get; private set; } public SecondViewModel() { SecondCommand = new MyICommand<string>(mySecondCommand); } public void mySecondCommand(string par) { Console.Beep(); } // 同样实现INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
2. 确保主ViewModel包含子VM实例
你提到View里有<ContentPresenter Content="{Binding Content}"/>,那假设你的主ViewModel(比如HomeViewModel)是承载这两个子VM的容器,你需要在主VM里实例化它们:
public class HomeViewModel : INotifyPropertyChanged { // 公开两个子ViewModel的属性 public FirstViewModel FirstVM { get; set; } public SecondViewModel SecondVM { get; set; } public object Content { get; set; } // 对应你View里ContentPresenter的绑定 public HomeViewModel() { // 初始化两个子VM FirstVM = new FirstViewModel(); SecondVM = new SecondViewModel(); // 这里初始化你的Content属性... } // 实现INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
3. 调整View里的按钮绑定路径
现在你的MainTreeView的DataContext应该是HomeViewModel实例,所以按钮的Command绑定需要指向主VM里的子VM属性,再找到对应的命令:
<Button Command="{Binding ElementName=MainTreeView, Path=DataContext.FirstVM.FirstCommand}" CommandParameter="{Binding NameE}"> <Label Content="{Binding NameE}"/> </Button> <Button Command="{Binding ElementName=MainTreeView, Path=DataContext.SecondVM.SecondCommand}" CommandParameter="{Binding NameD}"> <Label Content="{Binding NameD}"/> </Button>
4. 确认MyICommand的实现正确性
最后要确保你的MyICommand正确实现了ICommand接口,不然命令也无法触发,这里给一个标准实现参考:
public class MyICommand<T> : ICommand { private readonly Action<T> _execute; private readonly Predicate<T> _canExecute; public MyICommand(Action<T> execute) : this(execute, null) { } public MyICommand(Action<T> execute, Predicate<T> canExecute) { _execute = execute ?? throw new ArgumentNullException(nameof(execute)); _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute == null || _canExecute((T)parameter); } public void Execute(object parameter) { _execute((T)parameter); } public event EventHandler CanExecuteChanged { add { CommandManager.RequerySuggested += value; } remove { CommandManager.RequerySuggested -= value; } } }
总结一下
只要修正构造函数的笔误,保证主ViewModel正确包含两个子VM的实例,并且绑定路径正确指向对应的命令,就能实现同一个View里的按钮分别绑定不同ViewModel的命令啦!
内容的提问来源于stack exchange,提问作者Filip Filipovic
相关产品推荐
相关产品推荐

