如何使用MVVM Light for WPF浏览窗口?

时间:2012-02-15 08:48:46

标签: wpf design-patterns mvvm mvvm-light

我刚刚开始了一个新项目,其中表示层将由WPF完成,MVVM Light由GalaSoft完成。

我需要很多观点,而且我不清楚如何通过窗口管理导航。

首先,MVVM Light中提供的用于创建新“WPF MVVM视图”的模板创建了一个新的Window,它不能用于逐帧导航(我的意思是,在{ {1}}并更改源路径以进行导航。

对于我使用模板创建的所有观看次数,我是否只需将mainView更改为Window

或者是否有不同的方法在WPF中使用MVVM Light工具包执行导航?

3 个答案:

答案 0 :(得分:20)

我通常使用ContentControl来显示动态内容。它的Content属性通常绑定到父CurrentViewModel中的ViewModel属性,而DataTemplates用于告诉WPF如何绘制子ViewModels

要更改视图,只需更改父CurrentViewModel

中的ViewModel属性即可

您可以在this article of mine

找到示例

答案 1 :(得分:14)

最终我这样做了。

遵循o_q的想法,我将NavigationWindow创建为MainWindow,并将所有视图更改为page。

然后,我使用Navigation创建了一个inteface和一个类:

public interface INavigationService
{
    event NavigatingCancelEventHandler Navigating;
    void NavigateTo(Uri pageUri);
    void GoBack();
}

public class NavigationService : INavigationService
{
    private NavigationWindow _mainFrame;

    #region Implementation of INavigationService

    public event NavigatingCancelEventHandler Navigating;
    public void NavigateTo(Uri pageUri)
    {

        if (EnsureMainFrame())
        {
            _mainFrame.Navigate(pageUri);
        }

    }

    public void GoBack()
    {
        if (EnsureMainFrame()
            && _mainFrame.CanGoBack)
        {
            _mainFrame.GoBack();
        }

    }

    #endregion

    private bool EnsureMainFrame()
    {
        if (_mainFrame != null)
        {
            return true;
        }

        _mainFrame = System.Windows.Application.Current.MainWindow as NavigationWindow;

        if (_mainFrame != null)
        {
            // Could be null if the app runs inside a design tool
            _mainFrame.Navigating += (s, e) =>
            {
                if (Navigating != null)
                {
                    Navigating(s, e);
                }
            };

            return true;
        }

        return false;
    }

}

然后,在viewModelLocator中,我创建了所有const字符串nedded以存储我的视图的路径:

public class ViewModelLocator
{

    #region Views Paths

    public const string FrontendViewPath = "../Views/FrontendView.xaml";
    public const string BackendViewPath = "../Views/BackendView.xaml";
    public const string StartUpViewPath = "../Views/StartUpView.xaml";
    public const string LoginViewPath = "../Views/LoginView.xaml";
    public const string OutOfOrderViewPath = "../Views/OutOfOrderView.xaml";
    public const string OperativeViewPath = "../Views/SubViews/OperativeView.xaml";
    public const string ConfigurationViewPath = "../Views/SubViews/ConfigurationView.xaml";
    #endregion

在App.cs中,在Application_Startup事件处理程序中,在Unity IoC的帮助下,我注册了一个NavigationService单例:

public partial class App : System.Windows.Application
{

    private static IUnityContainer _ambientContainer;
    public static IServiceLocator AmbientLocator { get; private set; }

    ...

   private void Application_Startup(object sender, System.Windows.StartupEventArgs e)
    {


       _ambientContainer =
           new UnityContainer();

       _ambientContainer.RegisterType<INavigationService, NavigationService>(new ContainerControlledLifetimeManager());

       AmbientLocator = new UnityServiceLocator(_ambientContainer);
       ServiceLocator.SetLocatorProvider(() => AmbientLocator);

现在,在我的ViewModelLocator中,我可以注册一个“Galasoft”消息来捕获所有事件并导航到一个页面;在我的构造函数中:

    public ViewModelLocator()
    {
        CreateMain();
        CreateFrontend();
        CreateBackend();
        CreateStartUp();
        CreateOperative();
        CreateLogin();
        CreateConfiguration();
        CreateOutOfOrder();


        // Set Sturtup Page...
        ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(StartUpViewPath, UriKind.Relative));

        Messenger.Default.Register<MoveToViewMessage>(this, message =>
        {
            switch (message.StateInfo.StateType)
            {
                case StateType.StartUpState:

                    ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(StartUpViewPath,UriKind.Relative));
                    break;
                case StateType.LoginState:
                    ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(LoginViewPath, UriKind.Relative));
                    break;
                case StateType.OperativeState:
                    ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(OperativeViewPath, UriKind.Relative));
                    break;
                case StateType.ConfigurationState:
                    ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(ConfigurationViewPath, UriKind.Relative));
                    break;
                case StateType.ClosedState:
                case StateType.OutOfOrderState:
                    ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(OutOfOrderViewPath, UriKind.Relative));
                    break;
                default:
                    ServiceLocator.Current.GetInstance<INavigationService>().NavigateTo(new Uri(StartUpViewPath, UriKind.Relative));
                    break;
            }
        });

    }

通过这种方式,我保持所有viewModel“无知”......他们对导航一无所知,而且我没有代码。

如果我需要使用视图中的按钮进行导航,我可以从连接的viewModel解析NavigationService并导航到我需要的页面。

最重要的是,它有效!

答案 2 :(得分:0)

对于可导航的应用,您希望启动视图为NavigationWindow而不是Window

<NavigationWindow
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    x:Class="MainWindow"
    Title="My Application Title"
    Height="300"
    Width="400" />

代码背后:

using System.Windows.Navigation;

public partial class MainWindow : NavigationWindow
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

MVVM Light视图模板使用Window,但正如您所猜测的那样,您只需更改它即可。如果您希望能够在此视图中导航,请将其设为Page。 这就是你的导航方式:

<Page
    x:Class="Page1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Page1">
    <Grid>
        <!-- this button will navigate to another page -->
        <Button
            Content="Go to Page 2"
            Click="Button_Click" />
    </Grid>
</Page>

代码背后:

using System.Windows;
using System.Windows.Controls;

public partial class Page1 : Page
{
    public Page1()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        // the Page class has a property "NavigationService" which allows you to navigate.
        // you can supply the "Navigate" method with a Uri or an object instance of the page 
        base.NavigationService.Navigate(new Page2());
    }
}