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

如何在ViewModel间访问属性?MVVM+Unity视图导航求助

解决WPF MVVM+Unity的用户控件导航问题

看起来你已经搭好了基础框架,现在核心问题集中在跨ViewModel的导航逻辑和接口定义不完整上,我来一步步帮你搞定:

1. 完善IMainViewModel接口

你当前的IMainViewModel是空接口,这导致LoginViewModel虽然注入了它,却没法访问ShowControl属性。我们需要把导航相关的属性暴露到接口里:

public interface IMainViewModel
{
    UserControl ShowControl { get; set; }
}

这样MainWindowViewModel实现接口时,ShowControl就会被子ViewModel识别并调用。

2. 把View注册到Unity容器

你现在只注册了主ViewModel,但LoginView和GameView还没加入容器,Unity没法解析它们。修改App.xaml.cs的ConfigureContainer方法:

private void ConfigureContainer()
{
    _container = new UnityContainer();
    // 注册主ViewModel为单例,确保全局唯一
    _container.RegisterType<IMainViewModel, MainWindowViewModel>(new ContainerControlledLifetimeManager());
    // 注册两个View,用相同生命周期管理器实现实例复用
    _container.RegisterType<LoginView>(new ContainerControlledLifetimeManager());
    _container.RegisterType<GameView>(new ContainerControlledLifetimeManager());
}

这样每次Resolve都会返回同一个实例,完全符合你不想重复创建对象的需求。

3. 修复LoginViewModel的导航逻辑

先修正命令名称的拼写错误(Navigae→Navigate),然后在execute方法里正确更新主ViewModel的ShowControl:

public class LoginViewModel : Bindable
{
    private IMainViewModel _mainViewModel;
    public ICommand Navigate { get; set; } // 修正拼写

    public LoginViewModel(IMainViewModel mainViewModel)
    {
        _mainViewModel = mainViewModel;
        Navigate = new RelayCommand(ExecuteNavigate, CanExecute);
        Display = "login view";
        MyData = "Gopi ";
    }

    private bool CanExecute(object arg) => true;

    private void ExecuteNavigate(object obj)
    {
        // 从Unity容器获取GameView实例并切换
        _mainViewModel.ShowControl = App.Container.Resolve<GameView>();
    }

    // 修复MyData的SetProperty调用,确保双向绑定能更新UI
    private string _myData;
    public string MyData
    {
        get => _myData;
        set => SetProperty(ref _myData, value);
    }

    private string _display;
    public string Display
    {
        get => _display;
        set => SetProperty(ref _display, value);
    }
}

4. 实现GameViewModel返回Login的逻辑

和LoginViewModel逻辑一致,在GameViewModel里注入IMainViewModel,添加返回命令:

public class GameViewModel : Bindable
{
    private IMainViewModel _mainViewModel;
    public ICommand NavigateBack { get; set; }

    public GameViewModel(IMainViewModel mainViewModel)
    {
        _mainViewModel = mainViewModel;
        NavigateBack = new RelayCommand(ExecuteNavigateBack, CanExecute);
        Display = "game view";
    }

    private bool CanExecute(object arg) => true;

    private void ExecuteNavigateBack(object obj)
    {
        // 切回已存在的LoginView实例
        _mainViewModel.ShowControl = App.Container.Resolve<LoginView>();
    }

    private string _display;
    public string Display
    {
        get => _display;
        set => SetProperty(ref _display, value);
    }
}

对应的GameView里添加返回按钮:

<Button Grid.Row="1" Content="Back to Login View" Command="{Binding NavigateBack}" />

5. 优化MainViewModel的初始化逻辑

你的ShowControl getter初始化可以简化,直接借助Unity的实例管理:

class MainWindowViewModel : Bindable, IMainViewModel
{
    private UserControl _showControl;
    public UserControl ShowControl
    {
        get
        {
            if (_showControl == null)
                _showControl = App.Container.Resolve<LoginView>();
            return _showControl;
        }
        set => SetProperty(ref _showControl, value);
    }
}

这样主窗口启动时会自动加载LoginView,完全符合你的初始需求。

验证效果

现在运行程序:

  • 主窗口初始显示LoginView
  • 点击"Navigate to Game View"按钮,切换到GameView
  • 点击GameView里的"Back to Login View"按钮,切回LoginView
  • 两个View的实例都是复用的,不会每次点击都创建新对象

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:11:25