我正在学习WPF MVVM并希望在主窗口点击按钮时打开一个新窗口。
我知道每个View都必须有一个等效的ViewModel,而MVVM的基本原则之一就是ViewModel一定不能了解View。
因此,任何人都可以向我提供一个简单的简洁示例,该示例不违反任何MVVM原则,如何创建两个具有以下功能的View和两个ViewModel:
单击主视图中的按钮显示新视图。
答案 0 :(得分:1)
您可以创建单独的服务以将视图作为对话框启动,以便可以在整个应用程序中以通用方式使用它。并将通过想要启动任何对话框的构造函数将此服务注入ViewModel。
public interface IDialogWindowService<T>
{
void Show();
void ShowDialog();
}
public class DialogWindowService<T> : IDialogWindowService<T> where T : Window
{
public void Show()
{
container.Resolve<T>().Show();
}
public void ShowDialog()
{
container.Resolve<T>().ShowDialog();
}
}
您可以创建单独的服务以将视图作为对话框启动,以便可以在整个应用程序中以通用方式使用它。并将通过想要启动任何对话框的构造函数将此服务注入ViewModel。
public interface IDialogWindowService<T>
{
void Show();
void ShowDialog();
}
public class DialogWindowService<T> : IDialogWindowService<T> where T : Window
{
public void Show()
{
container.Resolve<T>().Show();
}
public void ShowDialog()
{
container.Resolve<T>().ShowDialog();
}
}
现在只需将此服务注入相应的viewmodel。
public class YourViewModel
{
//commands
public ICommand someCommand { get; set; }
private IDialogWindowService<BookingView> _dialogService;
public YourViewModel(IDialogWindowService<YourView > dialogService)
{
_dialogService = dialogService
someCommand = new RelayCommand(someCommandDoJob, () => true);
}
public void someCommandDoJob(object obj)
{
//Since you want to launch this view as dialog you can set its datacontext in its own constructor.
_dialogService.ShowDialog();
}
}
或强>
您可以使用DataTemplates
更改视图。它允许根据Views
:
ViewModel
<Window>
<Window.Resources>
<DataTemplate DataType="{x:Type ViewModelA}">
<localControls:ViewAUserControl/>
</DataTemplate>
<DataTemplate DataType="{x:Type ViewModelB}">
<localControls:ViewBUserControl/>
</DataTemplate>
<Window.Resources>
<ContentPresenter Content="{Binding CurrentView}"/>
</Window>
如果Window.DataContext是ViewModelA的实例,则会显示ViewA并
Window.DataContext是ViewModelB的一个实例,然后将显示ViewB。
我见过并阅读过的最好的例子是由Rachel Lim制作的。 See the example.
答案 1 :(得分:0)
根据您的使用情况,从视图的代码隐藏中打开视图没有任何问题。毕竟它仍然是查看代码。
MyView view = new MyView();
view.Show();
否则,如果您需要从ViewModel
或使用ICommand
打开一个窗口,那么您可以查看&#34;在MVVM中打开Windows和对话框&#34; 我在GitHub上写的库。这将演示如何通过使用MVVM设计模式单击按钮来打开Window
。
答案 2 :(得分:0)
我过去取得的一些成功所做的就是创建一个基本上是View Factory的东西,构建一个视图并为它指定一个视图模型。这给了我一个一站式的商店来做意见,就像你使用IoC一样。
这可能有利有弊,所以我很想知道是否有其他/更好的方法,但到目前为止,这是我发现最不痛苦的做法。
答案 3 :(得分:0)
Window newWindow = new Window();
Window.Show();
或者如果要禁用上一个窗口
Window newWindow = new Window();
Window.ShowDialog();
答案 4 :(得分:0)
要使MVVM更纯净,可以使用工厂或为每个视图编写一个接口驱动的控制器,以处理a)显示内容和b)如何将其绑定到数据。因此对于控制器:FormAlpha具有FormAlphaViewModel和FormAlpha.VPS。该接口非常适合此操作,因为每个实现都不同。
因此,请创建一个标准,使每个视图都具有以vps或可视表示服务结尾的界面驱动类。您想在该按钮单击上触发FormAlpha。您将使用反射或工厂将FormAlpha.vps加载为IVisualPresentor并调用IVisualPrentor.Display(parms);。
每个VPS都有加载特定表单,将数据绑定与与该表单关联的视图模型绑定的工作(没有提供很多解决方案),并且第一个参数始终具有Show()或ShowDialog()的必需参数。
而且...当然...您的viewmodel首先要传递的参数是。因此,VPS将分解这些参数并确认已传递正确的参数。通过这种方式(从您的示例中),您可以拥有按钮代表的功能并想要部署。 VPS处理完成此任务所需的数据和视觉效果。呼叫者只知道VPS将处理任何功能。现在,我只是从内存中弄乱了下面的代码,所以它不是完美的。但是请在上面提出我正在谈论的想法。
public interface IVisualPresentor
{ void Display(params object[] parms) };
public class FormAlpha.VPS : IVisualPresentor
{
public void Display(params object[] parms)
{
//validate parms if needed and cast to type specific data
//for example it needs session data parms[1] and customer parms[2]
var form = new FormAlpha();
var model = new FormAlphaViewModel( sessionData, customer );
form.DataBinding = model;
if ((bool)parms[0])
form.Show();
else
form.ShowDialog();
}
}
答案 5 :(得分:-2)
假设Form1是您的主要表单,Form2是您要打开的表单: 您可以使用此代码(将其插入Form1):
Form2 frm = new Form2();
frm.Show();
此外,如果您想关闭主表单,可以使用this.Close();
(它将关闭当前表单)。
此外,如果您只想打开Form2,但仍然可以使用Form1作为主要的:
Form2 frm = new Form2();
frm.Show();
this.Focus();