如何从弹出窗口更改主窗口视图

时间:2022-10-01 07:15:46

I'm trying to learn MVVM but am finding it a nightmare trying to understand how to correctly navigate between views in an application using MVVM. After some time researching and trying to understand different techniques I have come across an approach from Rachel Lim's blog. This technique uses a ViewModel for the application itself and keeps track of the application state such as the current page. I feel this would be a nice approach to follow for my application.

我正在尝试学习MVVM,但我发现这是一个噩梦,试图理解如何在使用MVVM的应用程序中正确导航视图之间。经过一段时间的研究和尝试理解不同的技术后,我遇到了Rachel Lim博客的方法。此技术将ViewModel用于应用程序本身,并跟踪应用程序状态,例如当前页面。我觉得这对我的应用程序来说是一个很好的方法。

Now moving onto my problem..

现在转向我的问题..

What I want to achieve

我想要实现的目标

I want an application that has a one main application view that will store a LoginView and a HomeView as DataTemplates and have a content control that sets the LoginView as the view displayed when the application is started. The LoginView will have a button that when pressed will open another window that has a button. When the button in the pop up window is pressed I want to change the view in the main application window from LoginView to the HomeView.

我想要一个具有一个主应用程序视图的应用程序,该视图将LoginView和HomeView存储为DataTemplates,并具有一个内容控件,将LoginView设置为应用程序启动时显示的视图。 LoginView将有一个按钮,按下该按钮将打开另一个有按钮的窗口。当按下弹出窗口中的按钮时,我想将主应用程序窗口中的视图从LoginView更改为HomeView。

What I have so far

到目前为止我有什么

I have a set up the ApplicationView which works fine.

我有一个设置ApplicationView的工作正常。

<Window x:Class="WPF_Navigation_Practice.Views.ApplicationView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:ignore="http://www.galasoft.ch/ignore"
        xmlns:vm="clr-namespace:WPF_Navigation_Practice.ViewModels"
        xmlns:views="clr-namespace:WPF_Navigation_Practice.Views"
        mc:Ignorable="d ignore"
        DataContext="{StaticResource ApplicationViewModel}">

    <Window.Resources>
        <DataTemplate DataType="{x:Type vm:LoginViewModel}">
            <views:LoginView />
        </DataTemplate>
        <DataTemplate DataType="{x:Type vm:HomeViewModel}">
            <views:HomeView />
        </DataTemplate>
    </Window.Resources>

    <Grid>
        <ContentControl Content="{Binding CurrentPageViewModel}" />
    </Grid>
</Window>

And have set up the ApplicationViewModel as follows. Setting the current page to the LoginViewModel.

并按如下方式设置了ApplicationViewModel。将当前页面设置为LoginViewModel。

using System.Collections.Generic;
using System.Linq;
using System.Windows.Input;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using WPF_Navigation_Practice.Interfaces;

namespace WPF_Navigation_Practice.ViewModels
{
    /// <summary>
    /// This class contains properties that a View can data bind to.
    /// <para>
    /// See http://www.galasoft.ch/mvvm
    /// </para>
    /// </summary>
    public class ApplicationViewModel : ViewModelBase
    {
        #region Fields

        private ICommand _changePageCommand;

        private IPageViewModel _currentPageViewModel;
        private List<IPageViewModel> _pageViewModels;

        #endregion

        public ApplicationViewModel()
        {
            // Add available pages
            PageViewModels.Add(new LoginViewModel());
            PageViewModels.Add(new HomeViewModel());
            PageViewModels.Add(new CodeViewModel());


            // Set starting page
            CurrentPageViewModel = PageViewModels[0];
        }

        #region Properties / Commands

        public ICommand ChangePageCommand
        {
            get
            {
                if (_changePageCommand == null)
                {
                    _changePageCommand = new RelayCommand<object>(
                        p => ChangeViewModel((IPageViewModel)p),
                        p => p is IPageViewModel);
                }

                return _changePageCommand;
            }
        }

        public List<IPageViewModel> PageViewModels
        {
            get
            {
                if (_pageViewModels == null)
                    _pageViewModels = new List<IPageViewModel>();

                return _pageViewModels;
            }
        }

        public IPageViewModel CurrentPageViewModel
        {
            get
            {
                return _currentPageViewModel;
            }
            set
            {
                if (_currentPageViewModel != value)
                {
                    _currentPageViewModel = value;
                    RaisePropertyChanged("CurrentPageViewModel");
                }
            }
        }


        #endregion

        #region Methods

        private void ChangeViewModel(IPageViewModel viewModel)
        {
            if (!PageViewModels.Contains(viewModel))
                PageViewModels.Add(viewModel);

            CurrentPageViewModel = PageViewModels
                .FirstOrDefault(vm => vm == viewModel);
        }

        #endregion
    }
}

When I run the application it will display my main Application window which displays the loginView which is a UserControl and is set as the currentPageViewModel with ContentPresenter.

当我运行应用程序时,它将显示我的主应用程序窗口,该窗口显示loginView,它是UserControl,并被设置为带有ContentPresenter的currentPageViewModel。

When the button in the LoginView UserControl is clicked it will open another window. As per the image below.

当单击LoginView UserControl中的按钮时,它将打开另一个窗口。如下图所示。

如何从弹出窗口更改主窗口视图

Here is the XAML for that window.

这是该窗口的XAML。

<Window x:Class="WPF_Navigation_Practice.Views.CodeView"
    x:Name="CodeWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:ignore="http://www.galasoft.ch/ignore"
    xmlns:z="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:viewModels="clr-namespace:WPF_Navigation_Practice.ViewModels"
    mc:Ignorable="d ignore"
    d:DesignWidth="623.224" d:DesignHeight="381.269"
    DataContext="{Binding CodeViewModel, Source={StaticResource ApplicationViewModel}}">

<Grid>
    <Button Content="Ok" 
            HorizontalAlignment="Left" 
            Margin="235,166,0,0" 
            VerticalAlignment="Top"
            Width="138" 
            FontSize="20" 
            Height="67"/>
    <Label Content="Second Window" HorizontalAlignment="Left" Margin="166,56,0,0" VerticalAlignment="Top" FontSize="36"/>
</Grid>

My Problem

我的问题

What I want to achieve is when the 'Ok' button in the secondView window is clicked, I want to change the currentPageViewModel in the ApplicationView Window from the LoginView to display the HomeView but am confused on how I would go about achieving this. Any help would be greatly appreciated.

我想要实现的是当单击第二个视图窗口中的“确定”按钮时,我想从LoginView更改ApplicationView窗口中的currentPageViewModel以显示HomeView,但我对如何实现这一点感到困惑。任何帮助将不胜感激。

1 个解决方案

#1


0  

I see that you are already using MVVMLight. There is a Messenger class which can help you here. Register to the messenger in your ApplicationViewModel Constructor and in the code handling the button click in CodeViewModel use Send to send a message. In the action you pass on to register change the viewmodels as you wish.

我看到你已经在使用MVVMLight了。有一个Messenger课程可以帮助你。在ApplicationViewModel构造函数中注册到messenger,在处理按钮的代码中单击CodeViewModel,使用Send发送消息。在您传递给注册的操作中,您可以根据需要更改视图模型。

See http://www.mvvmlight.net/help/WP8/html/9fb9c53a-943a-11d7-9517-c550440c3664.htm and Use MVVM Light's Messenger to Pass Values Between View Model

请参阅http://www.mvvmlight.net/help/WP8/html/9fb9c53a-943a-11d7-9517-c550440c3664.htm并使用MVVM Light的Messenger在视图模型之间传递值

I don't have MVVMLight to write you a sample code. I've written a ViewModelMessenger from scratch and mine is like this:

我没有MVVMLight给你写一个示例代码。我从头开始编写ViewModelMessenger,我的是这样的:

public static void Register(string actionName, object registerer, Action<object, object> action)
{
    var actionKey = new Tuple<string, object>(actionName, registerer);
    if (!RegisteredActions.ContainsKey(actionKey))
    {
        RegisteredActions.Add(actionKey, action);
    }
    else
    {
        RegisteredActions[actionKey] = action;
    }
}

Used like:

使用如下:

VMMessenger.Register("ChangeViewModel",this,ChangeViewModelAction)

and

public static void SendMessage(string messageName, object message, object sender)
{
    var actionKeys = RegisteredActions.Keys.ToList();
    foreach (Tuple<string, object> actionKey in actionKeys)
    {
        if (actionKey.Item1 == messageName)
        {
            Action<object, object> action;
            if (RegisteredActions.TryGetValue(actionKey, out action))
            {
                action?.Invoke(message, sender);
            }
        }
    }
}

Used like:

使用如下:

VMMessenger.SendMessage("ChangeViewModel","HomeViewModel",this);

and in ChangeViewModelAction you can check for ViewModel names and change the CurrentPageViewModel to one with a matching name.

在ChangeViewModelAction中,您可以检查ViewModel名称并将CurrentPageViewModel更改为具有匹配名称的名称。

#1


0  

I see that you are already using MVVMLight. There is a Messenger class which can help you here. Register to the messenger in your ApplicationViewModel Constructor and in the code handling the button click in CodeViewModel use Send to send a message. In the action you pass on to register change the viewmodels as you wish.

我看到你已经在使用MVVMLight了。有一个Messenger课程可以帮助你。在ApplicationViewModel构造函数中注册到messenger,在处理按钮的代码中单击CodeViewModel,使用Send发送消息。在您传递给注册的操作中,您可以根据需要更改视图模型。

See http://www.mvvmlight.net/help/WP8/html/9fb9c53a-943a-11d7-9517-c550440c3664.htm and Use MVVM Light's Messenger to Pass Values Between View Model

请参阅http://www.mvvmlight.net/help/WP8/html/9fb9c53a-943a-11d7-9517-c550440c3664.htm并使用MVVM Light的Messenger在视图模型之间传递值

I don't have MVVMLight to write you a sample code. I've written a ViewModelMessenger from scratch and mine is like this:

我没有MVVMLight给你写一个示例代码。我从头开始编写ViewModelMessenger,我的是这样的:

public static void Register(string actionName, object registerer, Action<object, object> action)
{
    var actionKey = new Tuple<string, object>(actionName, registerer);
    if (!RegisteredActions.ContainsKey(actionKey))
    {
        RegisteredActions.Add(actionKey, action);
    }
    else
    {
        RegisteredActions[actionKey] = action;
    }
}

Used like:

使用如下:

VMMessenger.Register("ChangeViewModel",this,ChangeViewModelAction)

and

public static void SendMessage(string messageName, object message, object sender)
{
    var actionKeys = RegisteredActions.Keys.ToList();
    foreach (Tuple<string, object> actionKey in actionKeys)
    {
        if (actionKey.Item1 == messageName)
        {
            Action<object, object> action;
            if (RegisteredActions.TryGetValue(actionKey, out action))
            {
                action?.Invoke(message, sender);
            }
        }
    }
}

Used like:

使用如下:

VMMessenger.SendMessage("ChangeViewModel","HomeViewModel",this);

and in ChangeViewModelAction you can check for ViewModel names and change the CurrentPageViewModel to one with a matching name.

在ChangeViewModelAction中,您可以检查ViewModel名称并将CurrentPageViewModel更改为具有匹配名称的名称。