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

基于MVVM模式实现WPF导航头部视图切换需求求助

WPF MVVM模式实现顶部导航+视图切换功能

要实现顶部固定导航、点击按钮切换底部视图,且子视图内按钮也能切换底部视图的需求,核心是用ContentControl绑定当前视图实例,配合MVVM模式的命令和属性通知来管理视图切换。以下是完整实现步骤:

1. 实现ViewModel基类

先创建一个实现INotifyPropertyChanged的基类,所有ViewModel都继承它,用于属性变化通知:

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

namespace WpfApp1
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

2. 创建命令基类(ICommand实现)

实现通用的RelayCommand,用于绑定按钮的命令逻辑:

using System;
using System.Windows.Input;

namespace WpfApp1
{
    public class RelayCommand : ICommand
    {
        private readonly Action<object> _execute;
        private readonly Func<object, bool> _canExecute;

        public event EventHandler CanExecuteChanged
        {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }

        public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
            _canExecute = canExecute;
        }

        public bool CanExecute(object parameter)
        {
            return _canExecute?.Invoke(parameter) ?? true;
        }

        public void Execute(object parameter)
        {
            _execute(parameter);
        }
    }
}

3. 创建子视图ViewModel

以View1、View2为例,子视图ViewModel包含切换到其他视图的命令,依赖主ViewModel管理当前视图:

namespace WpfApp1
{
    public class View1ViewModel : ViewModelBase
    {
        private readonly MainViewModel _mainViewModel;

        public ICommand SwitchToView2Command { get; }

        public View1ViewModel(MainViewModel mainViewModel)
        {
            _mainViewModel = mainViewModel;
            SwitchToView2Command = new RelayCommand(_ => _mainViewModel.CurrentViewModel = new View2ViewModel(_mainViewModel));
        }
    }

    public class View2ViewModel : ViewModelBase
    {
        private readonly MainViewModel _mainViewModel;

        public ICommand SwitchToView1Command { get; }

        public View2ViewModel(MainViewModel mainViewModel)
        {
            _mainViewModel = mainViewModel;
            SwitchToView1Command = new RelayCommand(_ => _mainViewModel.CurrentViewModel = new View1ViewModel(_mainViewModel));
        }
    }
}

4. 创建主ViewModel

主ViewModel负责管理当前显示的视图,以及顶部导航按钮的命令:

namespace WpfApp1
{
    public class MainViewModel : ViewModelBase
    {
        private ViewModelBase _currentViewModel;

        public ViewModelBase CurrentViewModel
        {
            get => _currentViewModel;
            set
            {
                _currentViewModel = value;
                OnPropertyChanged();
            }
        }

        public ICommand SwitchToView1Command { get; }
        public ICommand SwitchToView2Command { get; }

        public MainViewModel()
        {
            // 默认显示View1
            CurrentViewModel = new View1ViewModel(this);
            SwitchToView1Command = new RelayCommand(_ => CurrentViewModel = new View1ViewModel(this));
            SwitchToView2Command = new RelayCommand(_ => CurrentViewModel = new View2ViewModel(this));
        }
    }
}

5. 创建子视图UserControl

创建View1.xaml:

<UserControl x:Class="WpfApp1.View1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfApp1"
             mc:Ignorable="d" 
             d:DesignHeight="400" d:DesignWidth="800">
    <Grid Background="LightBlue">
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Label Content="这是View1内容" FontSize="24"/>
            <Button Content="切换到View2" Margin="0,20,0,0" Command="{Binding SwitchToView2Command}"/>
        </StackPanel>
    </Grid>
</UserControl>

创建View2.xaml:

<UserControl x:Class="WpfApp1.View2"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfApp1"
             mc:Ignorable="d" 
             d:DesignHeight="400" d:DesignWidth="800">
    <Grid Background="LightGreen">
        <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
            <Label Content="这是View2内容" FontSize="24"/>
            <Button Content="切换回View1" Margin="0,20,0,0" Command="{Binding SwitchToView1Command}"/>
        </StackPanel>
    </Grid>
</UserControl>

6. 配置主窗口XAML

修改MainWindow.xaml,设置DataContext,顶部按钮绑定命令,底部用ContentControl绑定当前视图,添加DataTemplate关联ViewModel和View:

<Window x:Class="WpfApp1.MainWindow"
        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:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:View1ViewModel}">
            <local:View1/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:View2ViewModel}">
            <local:View2/>
        </DataTemplate>
    </Window.Resources>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <!-- 顶部导航栏 -->
        <Grid Grid.Row="0" Background="Red">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Button Grid.Column="0" Content="View 1" Margin="4" Command="{Binding SwitchToView1Command}"/>
            <Button Grid.Column="1" Content="View 2" Margin="4" Command="{Binding SwitchToView2Command}"/>
        </Grid>

        <!-- 底部视图容器 -->
        <ContentControl Grid.Row="1" Content="{Binding CurrentViewModel}"/>
    </Grid>
</Window>

实现说明

  • 顶部导航栏和子视图内的按钮都通过绑定ICommand触发视图切换,所有逻辑在ViewModel中处理,符合MVVM关注点分离原则。
  • ContentControl会根据CurrentViewModel的类型自动匹配对应的DataTemplate渲染视图,无需手动控制可见性。
  • 顶部布局始终固定,仅ContentControl区域随CurrentViewModel变化更新内容。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 09:55:14