如何使用 MVVM Light Toolkit 打开新窗口

发布于 2024-09-12 14:26:08 字数 790 浏览 4 评论 0原文

我在 WPF 应用程序中使用 MVVM Light 工具包。我想知道从现有窗口打开新窗口的最佳方法是什么。我有这个 MainViewModel,它负责我的应用程序的 MainWindow。现在,在 MainView 中,单击按钮后,我想在其顶部打开第二个窗口。我已将 RelayCommmand 绑定到 ButtonCommand。在 RelayCommand 的方法中,我可以创建一个新的窗口对象并简单地调用 Show(),如下所示:

var view2 = new view2()
view2.Show()

但我认为 ViewModel 不应该负责用于创建新的 view2 对象。我已阅读这篇文章 WPF MVVM Get Parent from VIEW MODEL 其中 Bugnion建议将消息​​从 viewmodel1 传递到 view1,然后 view1 应创建新的 view2。但我不确定他将消息传递给 view1 到底是什么意思? view1 应该如何处理该消息?在它的代码后面还是什么?

问候, 纳比尔

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:

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 MODEL where 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?

Regards,
Nabeel

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

回眸一遍 2024-09-19 14:26:08

将消息从 ViewModel1 传递到 View1 意味着使用 MVVM Light Toolkit 中的消息传递功能

例如,您的 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 将在其后台代码中注册接收消息,并在收到正确消息时显示 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();
        }
    }
}

Passing a message from ViewModel1 to View1 means to use the messaging capabilities in the MVVM Light Toolkit.

For example, your ViewModel1 could have a command called ShowView2Command, then it would send a message to display the view.

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.

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();
        }
    }
}
空城缀染半城烟沙 2024-09-19 14:26:08

你为什么走这条路?很简单。如果您将按钮替换为切换按钮、超链接或任何其他数量的类似按钮的控件,则无需更新“代码隐藏” - 这是 MVVM 模式的基本原则。在新的切换按钮(或其他)中,您最终仍然会绑定到相同的命令。

例如,我正在为一位想要拥有 2 个 UI 的客户创建一个项目 - 其中一个在各方面(在演示方面)都将完全不同。水平选项卡与垂直 RadPanelBar(想想手风琴)用于导航。这两个视图都可以指向相同的 viewModel - 当用户单击视图 1 中的“工作订单”选项卡时,它会触发与面板栏中的“工作订单标题”中触发的相同“WorkOrderCommand”。

在代码隐藏模型中,您必须编写两个单独的事件。在这里你只需要编写一个代码。

此外,它允许设计师使用 Blend 创建他们想要的任何布局。只要他们有钩子(EventToCommand 控件),我(作为开发人员)就不会关心最终产品的外观。

松耦合的力量非常强大。

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.

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.

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.

Loose coupling is incredibly powerful.

﹂绝世的画 2024-09-19 14:26:08

您可以这样做,就像您需要创建一些事件并在视图中注册这些事件并在视图模型中调用它们一样。然后打开该弹出窗口。

这个示例

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");
    } 
}

就像视图中的

MainView mn=new MainView();在此处注册事件,就像 mn.POpUpEvent += 一样,单击选项卡按钮两次

并在寄存器弹出窗口中 注册事件方法右侧打开弹出窗口的代码。

You can do in this way like you need to create some events and register those in view and 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();

Register the event here like thake mn.POpUpEvent += than click on tab button double time

and in registers popup method right the code for opening the pop up window.

金兰素衣 2024-09-19 14:26:08

除非我错过了这里的要点 - 如果我要使用后面的代码,那么为什么不直接实现button_click事件并打开第二个视图呢?

Bugnion 似乎建议的是 view1 ->按钮点击->中继命令->视图模型1 ->留言->视图1-> view1.cs->开放视图 2.

无论如何,通过编写代码隐藏都会牺牲可测试性,所以为什么要走这么长的路呢?

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?

What Bugnion seems to be suggesting is view1 -> button click -> relay command -> viewmodel1 -> message -> view1 -> view1.cs -> open view 2.

You are going to sacrifice testability anyhow by writing code-behind, so why take such a long route?

舟遥客 2024-09-19 14:26:08

您可以使用通用接口将视图特定功能抽象为服务。在视图层中,您可以提供这些服务的具体实例,并使用 IoC 容器和依赖注入技术构建视图模型。

在您的情况下,您可以构建一个接口 IWindowManager 或具有所需方法的类似接口。这可以在您的视图层中实现。我最近写了一篇小博文,演示如何从视图模型中抽象出对话框行为。类似的方法可用于任何与用户界面相关的服务,例如导航、消息框等。

此链接可能对您有帮助 http://nileshgule.blogspot.com/2011/05/silverlight-use-dialogservice-to.html

许多人还使用从视图模型触发事件的方法,这些方法是订阅 view.cs 文件,然后执行 MessageBox 或任何其他 UI 相关操作。我个人喜欢注入服务的方法,因为这样您就可以提供同一服务的多个实现。一个简单的例子是如何在 Silverlight 和 Windows Phone 7 应用程序中处理导航。您可以使用相同的视图模型,但根据应用程序类型注入导航服务的不同实现。

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.

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.

This link might be helpful for you 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.

半暖夏伤 2024-09-19 14:26:08

我发现解决这个问题的最佳方法是从 ViewModel 打开和关闭窗口。作为这个 链接建议,

  1. 创建一个 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);
        }
    }
  1. 创建一个继承自 GalaSoft.MvvmLight.ViewModelBase 的 Base 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;
        }));
    }
  1. 在视图中,将 DialogCloser.DialogResult 依赖项属性与基础视图模型中的 CloseWindowFlag 属性绑定。

然后您可以从视图模型中打开/关闭/隐藏窗口。

I find the best way to approach this, is opening and closing the window from the ViewModel. As this link suggests,

  1. Create a DialogCloser class
    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);
        }
    }
  1. Create a Base ViewModel inheriting from GalaSoft.MvvmLight.ViewModelBase with there additional members. Once done, use this viewmodel as base for other viewmodels.
    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;
        }));
    }
  1. In the view, Bind the DialogCloser.DialogResult dependency property with the CloseWindowFlag property in the base viewmodel.

Then you can open/close/hide the window from the viewmodel.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文