c# - 如何在 WPF 中使用 MVVM 在页面和打开的窗口之间导航?

标签 c# wpf xaml mvvm

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

> Visual Studio Community 2019 
> .NET Framework: 4.7.2
为简单起见,我有 3 页和 1 个窗口 对于 KIOSK 应用程序,所有 View 都是全屏的 .详情页面如下:
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 的教程:-
  • Navigating between views in WPF / MVVM
  • Navigation with MVVM
  • MVVMTest

  • 每篇文章都使用不同的方法,由于我不熟悉它,一旦出现错误行并且没有 Intellisense 建议,我将无法继续找到解决方案。
    如果我有多个页面和窗口屏幕,是否很难在 WPF 中使用 MVVM?目前,我有一个完整的 WPF 应用程序,但它使用代码隐藏。我想转向 MVVM,因为我已经读到 MVVM 比某处的代码隐藏更好。单页的 MVVM 不是我以前做过的问题,使用 MVVM 时它非常棒。
    如果导航几乎不可能得到可行的答案,我是否应该保留在 WPF 中使用代码隐藏?

    最佳答案

    开始简单并设置navigationservice、viewmodellocators 和除基础之外的所有东西现在放在一边。
    无论如何,我会避免所有那些....定位器类。他们必然依赖于反模式 IMO。
    只需先使用 viewmodel 和单个窗口应用程序。
    基本模式涉及一个 MainWindow,其 Datacontext 是 MainWindowViewModel。
    您可能需要一个菜单​​或类似的菜单,但您要切换的部分是 contentcontrol 的内容。
    将 ContentControl 的 Content 属性绑定(bind)到 mainwindowviewmodel 上的公共(public)对象属性。为讨论起见,调用该 CurrentViewModel。
    每个 View 定义一个 View 模型和用户控件,您将在它们之间切换。因此 HomeView 和 HomeViewModel、LoginView 和 LoginViewModel。等等。
    在资源字典中,为每个 View 创建一个数据模板,将您的用户控件与其 View 模型的类型相关联。
    在 app.xaml 中合并此资源字典。
    导航。
    实例化您需要的那种新的 View 模型。
    将 CurrentViewModel 设置为该实例。
    然后它将被模板化到 UI 中。
    这有很多变体——它首先被称为 View 模型,你应该能够轻松地在谷歌上搜索一些示例。
    这是我写的一个稍微不同的目的:
    https://social.technet.microsoft.com/wiki/contents/articles/52485.wpf-tips-and-tricks-using-contentcontrol-instead-of-frame-and-page-for-navigation.aspx
    如果你真的想要页面,你可以对页面使用类似的方法:
    简化 View :

        <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>
    
    非常简化的 View 模型。
        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。
    我希望这是足够的信息而不是压倒性的。既要清楚又不要淹没有信息的人,这很棘手。

    关于c# - 如何在 WPF 中使用 MVVM 在页面和打开的窗口之间导航?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63065795/

    相关文章:

    c# - 更新对象的通用方法错误( Entity Framework 4)

    c# - 如何为我的 UserControl 绑定(bind)不同的 DataContext?

    wpf gridsplitter问题——两边都缩小

    c# - WPF-如何使用ViewModel的ObservableCollection显示TabItem?

    c# - 从字符串映射枚举

    c# - 私有(private)方法的最佳实践命名是什么?

    c# - WPF 实际宽度为零

    c# - WPF 验证错误 : How to show in separate TextBlock, 不在工具提示中

    C#无法在单击按钮时隐藏标签

    wpf - BindingExpression(路径)错误会影响性能吗?