繁体   English   中英

WPF mvvm 导航的另一种方式

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM