【发布时间】:2016-02-28 21:25:23
【问题描述】:
我可能错过了这里的重点,我已经挖掘了一段时间,查看了the different approaches 来绑定视图和视图模型以及如何在它们之间导航。
设置:
- 1 个主窗口(ViewModel:
MainWindowViewModel) - MainWindow 包含一些视觉效果和绑定到
ViewModelBase的ContentControl。所以在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 中设置对它的引用。不过对这个实现并不完全满意。