wpf 如何使用 MVVM Light Toolkit 打开新窗口
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3386349/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to open a new window using MVVM Light Toolkit
提问by nabeelfarid
I am using MVVM Light toolkit in my WPF application. I would like to know what is the best approach for opening a new window from an existing window. I have got this MainViewModel
, which is responsible for MainWindow
of my application. Now in the MainView
, on a button click, I would like to open a second window on top of it. I have got RelayCommmand
binded to the Button
's Command
. In the RelayCommand
's method, I can create a new window object and simply call Show()
, something like this:
我在我的 WPF 应用程序中使用 MVVM Light 工具包。我想知道从现有窗口打开新窗口的最佳方法是什么。我有这个MainViewModel
,它负责MainWindow
我的应用程序。现在MainView
,在单击按钮时,我想在它上面打开第二个窗口。我有RelayCommmand
绑定到Button
的Command
。在RelayCommand
的方法中,我可以创建一个新的窗口对象并简单地调用Show()
,如下所示:
var view2 = new view2()
view2.Show()
but I don't think the ViewModel should be responsible for creating the new view2
object. I have read this post WPF MVVM Get Parent from VIEW MODELwhere Bugnion has suggested to pass message to the view1
from the viewmodel1
and then view1
should create the new view2
. But I am not sure what does he actually mean by passing the message to the view1
? How should the view1
handle the message? In it's code behind or what?
但我不认为 ViewModel 应该负责创建新view2
对象。我看到这篇文章WPF MVVM获取从视图模型父那里比尼翁曾建议传递消息给view1
从viewmodel1
后view1
应该创建新的view2
。但我不确定他将消息传递给view1
? 应该如何view1
处理消息?在它的代码后面还是什么?
Regards, Nabeel
问候, 纳比尔
回答by Matt Casto
Passing a message from ViewModel1 to View1 means to use the messaging capabilities in the MVVM Light Toolkit.
将消息从 ViewModel1 传递到 View1 意味着使用MVVM Light Toolkit 中的消息传递功能。
For example, your ViewModel1 could have a command called ShowView2Command, then it would send a message to display the view.
例如,您的 ViewModel1 可能有一个名为 ShowView2Command 的命令,然后它会发送一条消息来显示视图。
public class ViewModel1 : ViewModelBase
{
public RelayCommand ShowView2Command { private set; get; }
public ViewModel1() : base()
{
ShowView2Command = new RelayCommand(ShowView2CommandExecute);
}
public void ShowView2CommandExecute()
{
Messenger.Default.Send(new NotificationMessage("ShowView2"));
}
}
View1 would register to receive messages in its code behind and display View2 when it receives the correct message.
View1 将注册以在其后面的代码中接收消息,并在接收到正确消息时显示 View2。
public partial class View1 : UserControl
{
public View1()
{
InitializeComponent();
Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
}
private void NotificationMessageReceived(NotificationMessage msg)
{
if (msg.Notification == "ShowView2")
{
var view2 = new view2();
view2.Show();
}
}
}
回答by Scott Silvi
Why do you go this route? Its simple. If you replace your button with a toggleButton, or a hyperlink, or any other number of button-like controls, you don't need to update your "code behind" - its a basic principle of the MVVM pattern. In your new toggleButton (or whatever), you still end up binding to the same exact Command.
你为什么走这条路?这很简单。如果您将按钮替换为 toggleButton、超链接或任何其他数量的类似按钮的控件,则无需更新“代码隐藏”——这是 MVVM 模式的基本原则。在您的新切换按钮(或其他)中,您最终仍会绑定到相同的命令。
For example, I'm creating a project for a client who wants to have 2 UI's - one is going to be fundamentally different in every way, in terms of presentation. Horizontal tabs vs Vertical RadPanelBar (think Accordion) for navigation. Both of these views can point to the same viewModel - when a user clicks the Work Order tab in View 1, it fires the same "WorkOrderCommand" that's fired in the Work Order Header in the panel bar.
例如,我正在为一个想要拥有 2 个 UI 的客户创建一个项目——一个在呈现方面在各个方面都将完全不同。用于导航的水平选项卡与垂直 RadPanelBar(想想手风琴)。这两个视图都可以指向同一个视图模型 - 当用户单击视图 1 中的工作订单选项卡时,它会触发在面板栏中的工作订单标题中触发的相同“WorkOrderCommand”。
In a code-behind model, you'd have to code two separate events. Here you only have to code one.
在代码隐藏模型中,您必须对两个单独的事件进行编码。在这里你只需要编码一个。
Furthermore, it allows a designer using Blend to create any layout they want. As long as they have the hooks (EventToCommand control) in place, myself (as a developer) couldn't care less what the final product looks like.
此外,它允许设计师使用 Blend 创建他们想要的任何布局。只要他们有钩子(EventToCommand 控件),我自己(作为开发人员)就不会关心最终产品的样子。
Loose coupling is incredibly powerful.
松耦合非常强大。
回答by Hoshiyar
You can do in this way like you need to create some events and register those in viewand call these in view model.and open that pop up window.
您可以通过这种方式进行操作,就像您需要创建一些事件并在视图中注册这些事件并在视图模型中调用它们一样。然后打开该弹出窗口。
Like This example
喜欢这个例子
public class Mainclass : MainView
{
public delegate abc RegisterPopUp(abc A);
public RegisterPopUp POpUpEvent ;
public RelayCommand ShowCommand { private set; get; }
public void ShowCommand()
{
ShowCommand("Your parameter");
}
}
inside the view MainView mn=new MainView();
视图内 MainView mn=new MainView();
Register the event here like thake mn.POpUpEvent +=
than click on tab button double time
在这里注册事件,而mn.POpUpEvent +=
不是双击标签按钮
and in registers popup method right the code for opening the pop up window.
并在注册弹出方法中正确打开弹出窗口的代码。
回答by Pratz
Unless I am missing the point here - if I were to use the code behind, then why not directly implement button_click event and open the second view?
除非我在这里遗漏了一点——如果我要使用后面的代码,那为什么不直接实现 button_click 事件并打开第二个视图呢?
What Bugnion seems to be suggesting is view1 -> button click -> relay command -> viewmodel1 -> message -> view1 -> view1.cs -> open view 2.
Bugnion 似乎建议的是 view1 -> 按钮单击 -> 中继命令 -> viewmodel1 -> 消息 -> view1 -> view1.cs -> 打开视图 2。
You are going to sacrifice testability anyhow by writing code-behind, so why take such a long route?
无论如何,您都将通过编写代码隐藏来牺牲可测试性,那么为什么要走这么长的路呢?
回答by Nilesh Gule
You can abstract the view specific features into services using generic interface. In the view layer you can provide concrete instances of these services and build view models using the IoC container and Dependency Injection technique.
您可以使用通用接口将视图特定功能抽象为服务。在视图层,您可以提供这些服务的具体实例,并使用 IoC 容器和依赖注入技术构建视图模型。
In your case you can build an interface IWindowManager or something similar which has the required method. This can be implmented in your view layer. I wrote a small blog post recently demonstrating how to abstract the dialog behaviour out of view model. Similar apporach can be used for any user interface related service like Navigation, MessageBoxes etc.
在您的情况下,您可以构建一个接口 IWindowManager 或类似的具有所需方法的东西。这可以在您的视图层中实现。我最近写了一篇小博文,展示了如何从视图模型中抽象对话框行为。类似的方法可用于任何用户界面相关服务,如导航、消息框等。
This link might be helpful for you http://nileshgule.blogspot.com/2011/05/silverlight-use-dialogservice-to.html
此链接可能对您有帮助http://nileshgule.blogspot.com/2011/05/silverlight-use-dialogservice-to.html
Many people also use the approach of firing events from view models which are subscribed on the view.cs file and from there the MessageBox or any other UI related action is performed. I personally like the approach of injecting services because then you can provide multiple implementations of the same service. A simple example would be how navigation is handled in Silverlight and Windows Phone 7 applications. You can use the same view model but inject different implementations of the Navigation service based on the application type.
许多人还使用从 view.cs 文件订阅的视图模型中触发事件的方法,并从那里执行 MessageBox 或任何其他与 UI 相关的操作。我个人喜欢注入服务的方法,因为这样您就可以提供同一服务的多个实现。一个简单的例子是如何在 Silverlight 和 Windows Phone 7 应用程序中处理导航。您可以使用相同的视图模型,但根据应用程序类型注入不同的导航服务实现。
回答by Touhid Alam
I find the best way to approach this, is opening and closing the window from the ViewModel. As thislink suggests,
我发现解决这个问题的最好方法是从 ViewModel 打开和关闭窗口。正如这个链接所暗示的那样,
- Create a
DialogCloser
class
- 创建一个
DialogCloser
班级
public static class DialogCloser { public static readonly DependencyProperty DialogResultProperty = DependencyProperty.RegisterAttached("DialogResult", typeof(bool?), typeof(DialogCloser), new PropertyMetadata(DialogResultChanged)); private static void DialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var window = d as Window; if (window != null) window.Close(); } public static void SetDialogResult(Window target, bool? value) { target.SetValue(DialogResultProperty, value); } }
- Create a Base ViewModel inheriting from
GalaSoft.MvvmLight.ViewModelBase
with there additional members. Once done, use this viewmodel as base for other viewmodels.
- 创建一个从
GalaSoft.MvvmLight.ViewModelBase
那里继承的基础 ViewModel和其他成员。完成后,使用此视图模型作为其他视图模型的基础。
bool? _closeWindowFlag; public bool? CloseWindowFlag { get { return _closeWindowFlag; } set { _closeWindowFlag = value; RaisePropertyChanged("CloseWindowFlag"); } } public virtual void CloseWindow(bool? result = true) { Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => { CloseWindowFlag = CloseWindowFlag == null ? true : !CloseWindowFlag; })); }
- In the view, Bind the
DialogCloser.DialogResult
dependency property with theCloseWindowFlag
property in the base viewmodel.
- 在视图中,将
DialogCloser.DialogResult
依赖属性与CloseWindowFlag
基础视图模型中的属性绑定。
Then you can open/close/hide the window from the viewmodel.
然后您可以从视图模型打开/关闭/隐藏窗口。