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

UWP C# MVVM架构下UserControl导航实现问题求助

UWP MVVM架构下UserControl导航问题解决方法

问题描述

在UWP项目中基于MVVM架构实现两个UserControl间的导航,通过AppController类的ChangeCurrentView方法切换MainPage中的UserControl,但该方法无效。相关代码如下:

AppController类代码

internal class AppController {
  public enum CurrentViewTypes {
    NotesList,
    AddEditNote,
  }

  public void ChangeCurrentView(CurrentViewTypes viewType) {
    switch (viewType) {
      case CurrentViewTypes.NotesList:
        NotesListViewModel sVM = new NotesListViewModel(this);
        NotesListView sV = new NotesListView();
        //привязка
        sV.DataContext = sVM;
        //отображение
        MainViewModel.CurrentView = sV;
        break;
      case CurrentViewTypes.AddEditNote:
        AddEditViewModel eVM = new AddEditViewModel(this);
        AddEditView eV = new AddEditView();
        //привязка
        eV.DataContext = eVM;
        //отображение
        MainViewModel.CurrentView = eV;
        break;
      default:
        throw new ArgumentOutOfRangeException(nameof(viewType));
    }
  }
}

App.xaml.cs启动代码

protected override void OnLaunched(LaunchActivatedEventArgs e) {
  MainPage mainPage = new MainPage();
  mainPage.DataContext = _controller.MainViewModel;
  Window.Current.Content = mainPage;
  Window.Current.Activate();
  _controller.ChangeCurrentView(AppController.CurrentViewTypes.NotesList);
}

MainPage.xaml绑定代码

<ContentPresenter Content="{Binding CurrentView}" />

参考WPF案例实现未成功,需解决UWP MVVM架构下的导航实现问题,确认是否采用单页切换UserControl的方式。


解决方案

核心问题分析

代码无效的关键原因:

  1. MainViewModel.CurrentView未实现属性变更通知:UWP绑定依赖INotifyPropertyChanged接口触发UI更新,直接赋值后UI无法感知变化。
  2. 违背MVVM职责分离:在控制器中直接创建View实例,导致View与ViewModel耦合,不符合MVVM架构原则。

正确实现步骤

1. 让MainViewModel实现INotifyPropertyChanged

确保属性变更时通知UI更新:

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

public class MainViewModel : INotifyPropertyChanged
{
    private object _currentView;
    public object CurrentView
    {
        get => _currentView;
        set
        {
            _currentView = value;
            OnPropertyChanged();
        }
    }

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

2. 采用ViewModel-first导航(符合MVVM)

通过DataTemplate关联ViewModel与View,控制器仅负责切换ViewModel:

  • 步骤1:在App.xaml中定义ViewModel与View的映射
<Application.Resources>
    <DataTemplate x:DataType="local:NotesListViewModel">
        <local:NotesListView />
    </DataTemplate>
    <DataTemplate x:DataType="local:AddEditViewModel">
        <local:AddEditView />
    </DataTemplate>
</Application.Resources>
  • 步骤2:修改AppController,仅切换ViewModel
internal class AppController {
    public enum CurrentViewTypes {
        NotesList,
        AddEditNote,
    }

    private readonly MainViewModel _mainViewModel;

    public AppController(MainViewModel mainViewModel)
    {
        _mainViewModel = mainViewModel;
    }

    public void ChangeCurrentView(CurrentViewTypes viewType) {
        switch (viewType) {
            case CurrentViewTypes.NotesList:
                _mainViewModel.CurrentView = new NotesListViewModel(this);
                break;
            case CurrentViewTypes.AddEditNote:
                _mainViewModel.CurrentView = new AddEditViewModel(this);
                break;
            default:
                throw new ArgumentOutOfRangeException(nameof(viewType));
        }
    }
}
  • 步骤3:调整App.xaml.cs,确保实例共享
private AppController _controller;

protected override void OnLaunched(LaunchActivatedEventArgs e) {
    var mainViewModel = new MainViewModel();
    _controller = new AppController(mainViewModel);
    
    MainPage mainPage = new MainPage();
    mainPage.DataContext = mainViewModel;
    Window.Current.Content = mainPage;
    Window.Current.Activate();
    
    _controller.ChangeCurrentView(AppController.CurrentViewTypes.NotesList);
}

3. 保留MainPage的ContentPresenter绑定

原MainPage.xaml的绑定代码无需修改,UWP会自动根据ViewModel类型匹配渲染对应的View:

<ContentPresenter Content="{Binding CurrentView}" />

导航方式选择

单页切换UserControl的方式完全适用于UWP,尤其适合小型应用或同一页面内的功能模块切换。若为大型应用,也可使用UWP自带的Frame进行页面级导航,但UserControl级导航采用上述ViewModel-first方式更贴合MVVM架构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 22:23:16