我不确定如何使用mvvm进行导航。我是初学者,所以我没有使用像mvvm light这样的任何框架。
我找到了很好的例子https://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/。但这并不是我正在寻找的,因为在我的应用程序中,每个视图都将涵盖所有窗口。因此,当我更改页面时,我将无法从主视图访问控件。
所以我决定制作一个用于更改ViewModel的MainViewModel(如在Rachel博客中),但每个ViewModel应该知道MainViewModel来执行更改视图。因此,当我创建PageViewModel时,我使用公共方法传递构造函数MainViewModel,例如,changeview()。
这是一个很好的方法吗?或者,也许,有更好的方法来实现这一目标吗?
答案 0 :(得分:0)
子视图模型不应该知道主视图模型。
相反,他们应该使用诸如前进或后退等名称来引发事件。 ChangeView是您提供的唯一示例,因此我们将继续使用它。
我们将让子viewmodel公开导致引发事件的命令。子视图的XAML中的按钮或MenuItem可以绑定到命令以允许用户调用它们。您也可以通过Click事件处理程序在后面的子视图代码中调用viewmodel方法来执行此操作,但命令更“正确”,因为在视图模型中稍微多做一些工作,它们使视图创建者的生活变得更加简单。
主视图模型处理这些事件并相应地更改活动页面视图模型。因此,child不是调用_mainVM.ChangeView(),而是提升自己的ChangeView事件,而子VM上该事件的主VM处理程序调用它自己的方法this.ChangeView()。主VM是组织者VM,因此它拥有导航。
将代码尽可能不可知地用于如何以及在何处使用是一个很好的规则。这适用于控件和视图模型。想象一下,如果ListBox类要求父级是某个特定的类;这将是令人沮丧的,也是不必要的。事件帮助我们编写有用的子类,这些子类不需要知道或关心哪个父类使用它们。即使重用不可能,这种方法也可以帮助您编写易于编写和维护的干净,分离良好的类。
如果您需要有关详细信息的帮助,请提供更多代码,我们可以将此设计应用于您的项目。
public class MainViewModel : ViewModelBase
{
public MainViewModel()
{
FooViewModel = new FooViewModel();
FooViewModel.Back += (object sender, EventArgs e) => Back();
}
public FooViewModel FooViewModel { get; private set; }
public void Back()
{
// Change selected page property
}
}
public class FooViewModel : ViewModelBase
{
public event EventHandler Back;
private ICommand _backCommand;
public ICommand BackCommand {
get {
if (_backCommand == null)
{
// It has to give us a parameter, but we don't have to use it.
_backCommand = new DelegateCommand(parameter => OnBack());
}
return _backCommand;
}
}
// C#7 version
public void OnBack() => Back?.Invoke(this, EventArgs.Empty);
// C# <= 5
//protected void OnBack()
//{
// var handler = Back;
// if (handler != null)
// {
// handler(this, EventArgs.Empty);
// }
//}
}
// I don't know if you already have a DelegateCommand or RelayCommand class.
// Whatever you call it, if you don't have it, here's a quick and dirty one.
public class DelegateCommand : ICommand
{
public DelegateCommand(Action<object> exec, Func<object, bool> canExec = null)
{
_exec = exec;
_canExec = canExec;
}
Action<object> _exec;
Func<object, bool> _canExec;
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return _canExec == null || _canExec(parameter);
}
public void Execute(object parameter)
{
if (_exec != null)
{
_exec(parameter);
}
}
}
如何从子XAML调用BackCommand
:
<Button Content="Back" Command="{Binding BackCommand}" />