【问题标题】:How to navigate between page and open window using MVVM in WPF?如何在 WPF 中使用 MVVM 在页面和打开的窗口之间导航?
【发布时间】:2020-07-24 02:17:27
【问题描述】:

我已经阅读了几篇文章、教程、示例。但我仍然无法在页面和窗口之间进行导航。

> Visual Studio Community 2019 
> .NET Framework: 4.7.2

为简单起见,我有 3 个页面和 1 个窗口所有视图都为 KIOSK 应用程序全屏显示。详情页面如下:

MVVMApps.sln
│
├── PageInitialize.xaml
├── PageHome.xaml
└──── PageSelectLanguage.xaml
               └── WinMessage.xaml

我尝试过 GalaSoft 的 MvvmLight,但一直无法从 PageInitialize.xaml 导航到 PageHome.xaml。我刚刚从GalaSoft 找到了一篇关于 WPF 即将推出INavigationService 的文章。我发现的大多数教程都是 Xamarin 的采样。

另外,我得到了未定义的程序集 using Microsoft.Practices.ServiceLocation;,我看到它在 Enterprise 上可用。在 Nuget 上,安装 MvvmLight 也会安装 CommonServiceLocator。

public class ViewModelLocator
{
    private static bool initialized;
    public ViewModelLocator()
    {
        //Fix to keep blend happy
        if (initialized) { return; }
        initialized = true;

        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
        SimpleIoc.Default.Register<MainViewModel>();
        SimpleIoc.Default.Register<PageInitializeViewModel>();
        SimpleIoc.Default.Register<PageHomeViewModel>();
        SimpleIoc.Default.Register<PageSelectLanguageViewModel>();
        SimpleIoc.Default.Register<WinMessageViewModel>();
        SetupNavigation();
    }

    public MainViewModel Main => ServiceLocator.Current.GetInstance<MainViewModel>();
    public PageInitializeViewModel PageInitializeViewModel => ServiceLocator.Current.GetInstance<PageInitializeViewModel>();
    public PageHomeViewModel PageHomeViewModel => ServiceLocator.Current.GetInstance<PageHomeViewModel>();
    public WinMessageViewModel WinMessageViewModel=> ServiceLocator.Current.GetInstance<WinMessageViewModel>();
    public static void Cleanup()
    {
        // TODO Clear the ViewModels
    }
    private void SetupNavigation()
    {
        var navigationService = new Helpers.NavigationService<Helpers.NavigationPage>();
        navigationService.ConfigurePages();
        SimpleIoc.Default.Register<Helpers.INavigationService<Helpers.NavigationPage>>(() => navigationService);
    }
}

我已经完成了一些没有 MvvmLight 的教程:-

  1. Navigating between views in WPF / MVVM
  2. Navigation with MVVM
  3. MVVMTest

每篇文章使用不同的方法,由于我不熟悉它,一旦出现错误行并且没有 Intellisense 建议,我将无法继续找到解决方案。

如果我有多个页面和窗口屏幕,是否很难在 WPF 中使用 MVVM?目前,我有一个完整的 WPF 应用程序,但它使用代码隐藏。我想转向 MVVM,因为我已经读到 MVVM 比某处的代码隐藏更好。单页的 MVVM 不是我以前做过的问题,而且在使用 MVVM 时非常棒。

如果导航几乎不可能得到可行的答案,我是否应该保留在 WPF 中使用代码隐藏?

【问题讨论】:

  • 如果是小应用,用后面的代码也没关系。 MVVM 背后的想法是您将业务逻辑与视图分离,因此您可以交换我们的视图,例如,您可能希望将 WPF 应用程序移动到 Web 应用程序中,使用 MVVM,理想情况下您只需要重写视图。在 WPF 中导航是不可能的吗?不,Prism (prismlibrary.com) 有很好的导航实现。我确信在 WPF 中有上百万种方法可以进行导航
  • @AthulRaj 是的,它是一个针对零售客户的小型应用程序,例如服务(快餐)。我想转向 MVVM,因为基本是我想体验和了解更多关于 MVVM 的信息。所以,这是一个更好的开始。 WPF 中的导航很简单。但是 MVVM 中的导航完全很难找到。我将探索 Prism 并对其进行一些研究,看看我能从中得到什么

标签: c# wpf xaml mvvm


【解决方案1】:

从简单的开始,将导航服务、视图模型定位器和除基础之外的所有内容暂时放在一边。

无论如何,我会避免所有那些 ....locator 类。他们必然依赖于反模式 IMO。

只需先使用 viewmodel 和单个窗口应用程序。

基本模式涉及一个MainWindow,其Datacontext是MainWindowViewModel。 您可能想要一个菜单​​或类似的东西,但您要切换的部分是 contentcontrol 的内容。

将 ContentControl 的 Content 属性绑定到 mainwindowviewmodel 上的公共对象属性。为讨论起见,调用该 CurrentViewModel。

为您将在其间切换的每个视图定义一个视图模型和用户控件。因此 HomeView 和 HomeViewModel、LoginView 和 LoginViewModel。以此类推。

在资源字典中,为每个视图创建一个数据模板,将您的用户控件与其视图模型的类型相关联。

在 app.xaml 中合并这个资源字典。

导航。

实例化您需要的新视图模型。

将 CurrentViewModel 设置为该实例。

然后它将被模板化到 UI 中。

这有很多变体 - 首先称为视图模型,您应该能够轻松地在谷歌上搜索一些示例。

这是我写的一个稍微不同的目的:

https://social.technet.microsoft.com/wiki/contents/articles/52485.wpf-tips-and-tricks-using-contentcontrol-instead-of-frame-and-page-for-navigation.aspx

如果你真的想要页面,你可以对页面使用类似的方法:

简化视图:

    <Window.DataContext>
        <local:MainWindowViewModel/>
    </Window.DataContext>
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:Page1ViewModel}">
            <local:Page1/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:Page2ViewModel}">
            <local:Page2/>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="120"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <ListBox Name="ViewSelect"
                 ItemsSource="{Binding ViewChoices}"
                 SelectedItem="{Binding SelectedViewChoice, Mode=TwoWay}"
                 >
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Frame Grid.Column="1"
               Content="{Binding SelectedViewChoice.VM}"
               NavigationUIVisibility="Hidden"
               />
    </Grid>
</Window>

非常简化的视图模型。

    public class MainWindowViewModel : INotifyPropertyChanged
    {
        public ObservableCollection<ViewChoice> ViewChoices { get; set; }
        = new ObservableCollection<ViewChoice>
        {
            new ViewChoice{ Name="Page One", VM=new Page1ViewModel()},
             new ViewChoice{ Name="Page Two", VM=new Page2ViewModel()},
        };

        private ViewChoice selectedViewChoice;

        public ViewChoice SelectedViewChoice
        {
            get { return selectedViewChoice; }
            set { selectedViewChoice = value; RaisePropertyChanged(); }
        }

ps

如果你决定学习 prism,我会从 delegatecommand 开始,直到你写了至少一个 wpf 应用程序。 PRISM 中有大量功能,大多数应用实际上并没有从区域和动态组合中受益。

如果您更喜欢 mvvmlight(我喜欢),那么对于核心,您最好获取源代码并使用它。您需要 commandWPF 命名空间,这依赖于 nuget 包中的 net old。不支持命令的版本可以很好的执行requery。

我希望这是足够的信息而不是压倒性的。既要清晰又不要淹没有信息的人,这很棘手。

【讨论】:

  • 我已经阅读了一些关于 MVVM 的答案,它的层次结构为 MvvmLight、Prism 和 MEF。我目前正在尝试使用您提到的那个。一件事是,在我当前的架构上,每个视图都有自己的计时器,它将在InitializedComponent() 之后初始化。在定时器命中时无响应,然后屏幕将自动返回首页。但是在每个视图模型类上,它首先会在我将视图模型类添加到MainWindowViewModel.ViewChoices 上的主持人时进行初始化。我正在考虑每个视图模型上的计时器、硬件初始化(现金接收器、卡终端、打印机)。有什么办法吗?
  • 当然。您可以传递对 mainwindowviewmodel 的引用并调用方法或使用 mvvmlight messenger 或任何中介。您可以添加依赖注入。构建一个基本视图模型,其中包含返回主页功能......各种。
  • 在你采用复杂的东西之前。想想你是否需要它。你需要MEF吗?客户端真的会从动态发现 dll 增加的复杂性中受益吗?也许你会为不同的客户提供不同的东西。如果你不这样做,那只是你开发的开销。先说简单。当您发现需要时,将事情复杂化。
  • 当然越简单越好。除非没有其他选择,否则我可能不需要复杂的东西。以前,我使用的是 MvvmLight。但我被困在如何导航到其他页面上。我已经设置了ViewModelLocator,但我不知道如何调用它。因为我以前从未做过带导航的 MVVM。只是没有导航的 MVVM 只是因为我想知道 MVVM 实际上是什么。
  • 您不需要 viewmodellocator。完全没有。或者至少你不太可能需要它。我经常使用 mvvmlight 并使用 viewmodel 第一导航。
猜你喜欢
  • 2021-12-08
  • 2012-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多