【问题标题】:WPF from ICommand back to MainViewWPF 从 ICommand 返回到 MainView
【发布时间】:2016-02-28 21:25:23
【问题描述】:

我可能错过了这里的重点,我已经挖掘了一段时间,查看了the different approaches 来绑定视图和视图模型以及如何在它们之间导航。

设置:

  • 1 个主窗口(ViewModel:MainWindowViewModel
  • MainWindow 包含一些视觉效果和绑定到ViewModelBaseContentControl。所以在MainWindowViewModel 我可以设置任何其他视图(模型)来显示。
  • 有两个用户控件,一个是登录表单,另一个是当前加载指示器。

在 App.xaml 中

<DataTemplate DataType="{x:Type vms:LoginViewModel}">
   <Views:LoginView />
    </DataTemplate>
<DataTemplate DataType="{x:Type vms:LoadingViewModel}">
        <Views:LoadingView />
    </DataTemplate>

目标:LoginViewModel 里面的ICommand 回到MainWindowViewModel,一个很长的表单数据。然后MainWindowViewModel 将切换到LoadingViewModel,对服务进行异步调用。下次启动时保存刷新令牌时,我将显示LoadingViewModel 而不是登录表单。完成后将打开一个新窗口(或其他内容,尚不知道)。

问题:大多数示例显示了当按钮位于两个用户控件之外时如何执行此操作,因此当 ICommand 在 MainWindow 内时,这很容易,但从调用事件子视图之一。使用 PropertyChange 似乎也有点过时了。

让我们深入研究一些代码,shell 我们?

MainWindow.xaml,只有重要的一行

<ContentControl Content="{Binding CurrentView}"  Grid.Column="1" Grid.Row="1" />

MainWindow.xaml.cs,在构造函数中

this.DataContext = new MainWindowViewModel();

主窗口视图模型

public class MainWindowViewModel
{
    public ViewModelBase CurrentView { get; set; }

    public MainWindowViewModel()
    {
        CurrentView = new LoginViewModel();
    }
}

登录视图模型

public class LoginViewModel : ViewModelBase
{
    public DelegateCommand loginCommand { get; set; }

    public LoginViewModel()
    {
        loginCommand = new DelegateCommand(Execute, CanExecute);
    }

    private bool CanExecute()
    {
        return true;
    }

    private void Execute()
    {
        //I need to go to MainWindowViewModel
        throw new NotImplementedException();
    }
    //more properties below heere.

ViewModelBase 继承自 BindableBase(来自 Prism),以便处理 PropertyChanged 事件。我的视图模型中的属性使用正确的SetProperty 方法。 我不喜欢使用 Prism 的区域、IEventAggregator 或 Unitiy。

解决方案

想到的是用构造函数发送一个长接口,并使用该接口对MainWindowViewModel进行“回调”,但我想这会出错,因为我会改变视图,从而设置MainWindowViewModel.CurrentView 到别的东西,留下 LoginViewModel 为空。由于请求来自该对象,我可以想象它不是很好。

【问题讨论】:

  • 如何在“ViewModelBase”的 getter 和 setter 中处理所有这些。这是您在异地时同时拥有新旧价值观的唯一地方。
  • 你做错了。没有 ViewModel 应该知道关于 View 的任何事情。整个想法是你的视图和视图模型应该完全分开,你应该能够完全改变你的视图或视图模型,它仍然应该工作。
  • @NawedNabiZada 是的,我知道。这就是我将 3 个视图模型分开的原因。我没有看到我在这里对 MVVM 做任何事情,直到现在它只是基本的实现。有时有一些要求使它少了一点 MVVM,也许这就是其中之一,但我正在寻找一个最适合 MVVM 的解决方案,当然还有可靠的代码。 XAMIMAX:嗯,这是 2 个不同的实例,我真的不需要旧值和新值。
  • 对我来说看起来非常完美的 MVVM。我自己使用回调,但我使用依赖注入框架(Ninject)来更轻松地促进单元测试。虽然您认为这可能存在问题还不是很清楚,但如果您将 CurrentView 设置为其他内容,那么为什么旧视图会调用回调?
  • 因为我想到的流程是LoginViewModel.someCommand -> callbackInterface.SomeMethod -> MainWindowViewModel.SomeMethod(实现接口)。 -> 将CurrentView 设置为LoadViewModel。因为我首先将 LoginViewModel 作为 CurrentView,所以我正在覆盖它,在我看来它会为空。但我想我会将其他视图模型作为单独的字段并在 CurrentView 中设置对它的引用。不过对这个实现并不完全满意。

标签: c# wpf xaml mvvm


【解决方案1】:

一种很好的沟通方式是 Messanger (MVVM Light) 或 EventAggregator (Prism) 概念。

它基本上是一个内存发布/订阅系统。

这是一个来自 MSDN 文章的示例

MVVM - Messenger and View Services in MVVM

Using the event aggregator pattern to communicate between view models

我不确定您使用的是哪个框架/库,但大多数 MVVM 框架都有类似的糟糕耦合通信概念。

这是处理通信的一个非常强大的概念。但是权力越大,责任越大=)...

HTH

【讨论】:

  • 谢谢,我知道这个概念,我在我的问题中提到我宁愿不使用它。我没有看过 MVVM Light,但我不喜欢 Prism 希望你用 eventAggregator 填充你的构造函数的方式。也许我以后会在其他场景中使用它。
猜你喜欢
  • 1970-01-01
  • 2013-08-05
  • 1970-01-01
  • 2012-06-11
  • 2019-01-19
  • 2015-04-02
  • 2017-06-10
  • 2012-05-09
  • 1970-01-01
相关资源
最近更新 更多