从ViewModel打开/关闭视图
本文关键字:视图 ViewModel 打开 | 更新日期: 2023-09-27 18:28:55
我有一个AddClientViewModel,它被两个视图(AddClientView和SuggestedAddressesView)引用。AddClientView是一个具有地址字段的表单。该表单有一个验证按钮,用于使用Geocoding验证输入的地址。如果返回多个地址,则会打开SuggestedAddressesView。
以下是我目前的做法:
AddClientViewModel:
private void ValidateExecute(object obj)
{
SuggestedAddresses = new ObservableCollection<DBHelper.GeocodeService.GeocodeResult>(GeoCodeTest.SuggestedAddress(FormattedAddress));
....
if (SuggestedAddresses.Count > 0)
{
var window = new SuggestedAddressesView(this);
window.DataContext = this;
window.Show();
}
}
这是AddClientViewModel从ViewModelBase 继承的SuggestedAddressesView构造函数
public SuggestedAddressesView(ViewModelBase viewModel)
{
InitializeComponent();
viewModel.ClosingRequest += (sender, e) => this.Close();
}
我遇到的另一个问题是,当我从AddClientViewModel调用OnClosingRequest()时。。。AddClientView和SuggestedAddressesView都关闭。我知道发生这种情况是因为两个视图都引用了相同的ViewModel。这不是我想要的行为。我希望能够独立关闭任一窗口。
从ViewModel打开视图是否是正确的MVVM结构?如何独立关闭窗口
一旦您从VM中引用UI元素(在本例中为View),您就违反了建议的MVVM准则。这样我们就可以知道在虚拟机中创建Window
对象是错误的。
所以现在开始纠正这个问题:
- 首先尝试保持1视图<->应用程序中有1个虚拟机。它更干净,并且允许您非常容易地切换具有相同逻辑的View实现。将多个视图添加到同一个虚拟机中,即使不是"突破性的",也会使其变得笨拙
- 现在您得到了
AddClientView
和SuggestedAddressesView
,它们有自己的VM。太棒了
从VM实现视图打开/关闭:
- 由于我们无法直接从虚拟机访问视图(以符合标准),当您需要打开/关闭视图并在视图中进行实际操作时,我们可以使用
Messenger
(MVVM Light)、EventAggregator
(PRISM)等方法从虚拟机向视图发送"消息" - 通过这种方式,VM只启动消息,并且可以对相同的操作进行良好的单元测试,并且不引用任何UI元素
使用"信使"方法处理Viewopen:
- 根据您的逻辑,
AddClientViewModel
必须要求打开SuggestedAddressesView
- 因此,当您检测到
SuggestedAddresses.Count > 0
时,您会向AddClientView
发送一条消息,要求其打开SuggestedAddressesView
- 在
AddClientView.xaml.cs
中,收到此消息后,您将执行当前在VM中执行的操作。创建一个SuggestedAddressesView
的对象,并对其调用.Show()
- 在上述步骤的过程中,您要添加的一个额外步骤是将
SuggestedAddressesView
的DataContext
分配为SuggestedAddressesViewModel
就是这样。现在,当AddClientViewModel
想要显示SuggestedAddressesView
时,它会向自己的View发送一条消息,View会创建并显示SuggestedAddressesView
。通过这种方式,虚拟机不引用任何视图,并且我们保持MVVM标准。
使用"信使"方法处理视图关闭:
- 关闭
View
非常简单。同样,当您需要从VM关闭视图时,您会向它自己的视图发送一条消息,要求关闭它 - 收到此消息后,View几乎会通过
.Hide()
/.Close()
关闭自己,或者以其他方式关闭它
在这个过程中,每个虚拟机都处理自己的视图关闭,并且没有任何相互连接的依赖关系。
您可以使用this作为起点,指导您处理此方法的"消息"。它附带了一个下载,您可以查看Messenger
的工作原理。这是MVVM Light,如果您不使用它或使用其他东西/您自己的MVVM实现,请将它作为指南,帮助您获得所需内容。
您可以使用RelayCommand,以便按如下方式发送参数:
Command="{Binding CloseWindowCommand, Mode=OneWay}"
CommandParameter="{Binding ElementName=TestWindow}"
使用此选项可以关闭各个视图。
示例:
public ICommand CloseCommand
{
get
{
return new RelayCommand(OnClose, IsEnable);
}
}
public void OnClose(object param)
{
AddClientView/SuggestedAddressesView Obj = param as AddClientView/SuggestedAddressesView;
obj.Close();
}
从ViewModel:打开窗口
创建NavigationService.cs类以打开窗口:让NavigationService.cs
现在将以下代码放入该类文件中。
public void ShowWindow1Screen(Window1ViewModel window1ViewModel)
{
Window1= new Window1();
Window1.DataContext = window1ViewModel;
Window1.Owner = Window1View;
Window1.ShowDialog();
}
那么。创建NavigationService.cs类MainWindowViewModel文件的实例。然后
Window1ViewModel window1ViewModel = new Vindow1ViewModel();
window1ViewModel.Name = MainWindowTextValue;
NavigationService navigationService = new NavigationService();
navigationService.ShowWindow1Screen(window1ViewModel);