You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合NavigationView实现MVVM?视图导航至ViewModel的方法

基于NavigationView的MVVM简易导航实现指导

核心逻辑很明确:你已经通过DataTemplate完成了ViewModel与View的关联,通过ContentControl绑定CurrentViewModel实现视图切换,剩下的就是在NavigationView.ItemInvoked事件中,根据选中的菜单项切换CurrentViewModel的实例——这就是MVVM模式下导航的核心。

以下是具体的分步实现:

1. 准备ViewModel基类(可选但推荐)

先封装一个实现INotifyPropertyChanged的基类,避免每个ViewModel重复写通知逻辑:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 实现主ViewModel(MainViewModel)

主ViewModel负责管理当前活跃的ViewModel,提供导航方法:

public class MainViewModel : ViewModelBase
{
    private object _currentViewModel;
    public object CurrentViewModel
    {
        get => _currentViewModel;
        set
        {
            _currentViewModel = value;
            OnPropertyChanged();
        }
    }

    // 根据标识切换ViewModel
    public void NavigateTo(string viewIdentifier)
    {
        switch (viewIdentifier)
        {
            case "Home":
                CurrentViewModel = new HomeViewModel();
                break;
            case "Settings":
                CurrentViewModel = new SettingsViewModel();
                break;
            // 扩展其他页面的case
        }
    }
}

3. 配置XAML布局

在主窗口的XAML中,完成NavigationView的菜单配置、DataTemplate关联,以及ContentControl的绑定:

<Window x:Class="YourAppNamespace.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:YourAppNamespace"
        Title="MVVM Navigation Demo" Height="450" Width="800">
    <!-- 设置主窗口的DataContext为主ViewModel -->
    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>

    <Grid>
        <!-- 定义ViewModel与View的映射 -->
        <Grid.Resources>
            <DataTemplate DataType="{x:Type local:HomeViewModel}">
                <local:HomeView />
            </DataTemplate>
            <DataTemplate DataType="{x:Type local:SettingsViewModel}">
                <local:SettingsView />
            </DataTemplate>
        </Grid.Resources>

        <NavigationView x:Name="MainNav" ItemInvoked="MainNav_ItemInvoked">
            <NavigationView.MenuItems>
                <!-- 用Tag属性标记对应的ViewModel标识 -->
                <NavigationViewItem Content="首页" Tag="Home" />
                <NavigationViewItem Content="设置" Tag="Settings" />
            </NavigationView.MenuItems>

            <!-- 绑定CurrentViewModel,自动渲染对应View -->
            <ContentControl Content="{Binding CurrentViewModel}" />
        </NavigationView>
    </Grid>
</Window>

4. 处理NavigationView的ItemInvoked事件

在主窗口的后台代码中,捕获菜单点击事件,调用主ViewModel的导航方法:

using System.Windows;

namespace YourAppNamespace
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            // 初始化时默认导航到首页
            (DataContext as MainViewModel)?.NavigateTo("Home");
        }

        private void MainNav_ItemInvoked(NavigationView sender, NavigationViewItemInvokedEventArgs args)
        {
            // 确保点击的是有效菜单项,且Tag为字符串标识
            if (args.InvokedItemContainer is NavigationViewItem navItem && navItem.Tag is string viewId)
            {
                // 调用ViewModel的导航方法切换视图
                (DataContext as MainViewModel)?.NavigateTo(viewId);
                // 更新NavigationView的选中状态
                MainNav.SelectedItem = navItem;
            }
        }
    }
}

关键注意事项

  • 每个自定义ViewModel必须对应一个DataTemplate,否则ContentControl无法自动渲染对应的View。
  • 如果需要传递导航参数,可以修改NavigateTo方法,在创建ViewModel实例时传入参数。
  • 避免在后台代码中直接创建View实例,所有视图切换逻辑都通过ViewModel的切换来完成,符合MVVM的职责分离原则。

内容的提问来源于stack exchange,提问作者Nathan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 21:55:27