[英]WPF mvvm navigation another way
我不确定如何使用 mvvm 进行导航。 我是初学者,所以我没有使用过任何框架,比如 mvvm light。
我找到了很好的例子https://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/ 。 但这并不是我正在寻找的,因为在我的应用程序中,每个视图都将覆盖所有窗口。 因此,当我更改页面时,我将无法从主视图访问控件。
所以我决定制作一个 MainViewModel 来更改 ViewModel(如 Rachel 博客中所述),但每个 ViewModel 都应该了解 MainViewModel 以执行更改视图。 因此,当我创建 PageViewModel 时,我使用公共方法(例如 changeview())传入构造函数 MainViewModel。
这是这样做的好方法吗? 或者,也许有更好的方法来实现这一目标?
子视图模型不应该知道主视图模型。
相反,他们应该使用诸如 Forward 或 Back 之类的名称来引发事件。 ChangeView 是您提供的唯一示例,因此我们将采用该示例。
我们将让子视图模型公开导致事件引发的命令。 子视图的 XAML 中的按钮或菜单项可以绑定到命令以让用户调用它们。 您也可以通过 Click 事件处理程序调用后面的子视图代码中的 viewmodel 方法来做到这一点,但命令更“正确”,因为以在 viewmodel 中做更多工作为代价,它们使视图创建者的生活变得更加简单.
主视图模型处理这些事件并相应地更改活动页面视图模型。 因此,子进程不是调用 _mainVM.ChangeView(),而是子进程引发自己的 ChangeView 事件,并且子进程上该事件的主 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}" />
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.