WPF 中的 ReactiveUI:RoutedViewHost 无法解析视图

ReactiveUI in WPF: RoutedViewHost Can't Resolve View

我最近接受了学习如何在 WPF 中构建应用程序的任务,并将 ReactiveUI 作为我的 MVVM 框架。我目前正在尝试在我的应用程序中练习实现路由器,我发现尽管遵循了“你、我和 ReactiveUI”中的示例,但我的 RoutedViewHost 没有显示视图,并抛出错误:

"System.Exception:'无法找到 'LearnReactiveUI.ViewModels.StartupViewModel' 的视图。'""

下面是我的主要 window (ReactiveWindow) 的 xaml,主体是 RoutedViewHost

<rxui:ReactiveWindow x:Class="LearnReactiveUI.Views.MainView"
        xmlns:rxui="http://reactiveui.net"
        xmlns:vms="clr-namespace:LearnReactiveUI.ViewModels"
        x:TypeArguments="vms:MainViewModel"
        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:LearnReactiveUI.Views"
        mc:Ignorable="d"
        Title="MainView" Height="450" Width="800">
    <Grid>
        <rxui:RoutedViewHost x:Name="routedViewHost"/>
    </Grid>
</rxui:ReactiveWindow>

这是我的 MainViewModel class,它创建了一个 RoutingState,然后导航到一个新的 StartupViewModel

using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LearnReactiveUI.ViewModels
{
    public class MainViewModel : ReactiveObject, IScreen
    {
        private readonly RoutingState routingState;
        public MainViewModel()
        {
           this.routingState = new RoutingState();

           routingState.Navigate.Execute(new StartupViewModel(this));
        }
        public RoutingState Router => this.routingState;
    }
}

最后这是我的 MainWindow 的代码隐藏,它将 Router 绑定到 RoutedViewHost

using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using LearnReactiveUI.ViewModels;
using System.Reactive.Disposables;

namespace LearnReactiveUI.Views
{
    public partial class MainView : ReactiveWindow<MainViewModel>
    {
        public MainView()
        {
            InitializeComponent();
            this.ViewModel = new MainViewModel();
            this.WhenActivated(disposables =>
                {
                    this
                        .OneWayBind(this.ViewModel, vm => vm.Router, v => v.routedViewHost.Router)
                        .DisposeWith(disposables);
                });
        }
    }
}

我的 Startup 视图的代码也很简单。这是 xaml

<rxui:ReactiveUserControl x:Class="LearnReactiveUI.Views.StartupView"
             xmlns:rxui="http://reactiveui.net"
             xmlns:vms="clr-namespace:LearnReactiveUI.ViewModels"
             x:TypeArguments="vms:StartupViewModel"
             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:LearnReactiveUI.Views"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Label Content="Startup" HorizontalAlignment="Center"
                   VerticalAlignment="Center" FontSize="72"/>
    </Grid>
</rxui:ReactiveUserControl>

这里是 StartupViewModel 的代码

using ReactiveUI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LearnReactiveUI.ViewModels
{
    public class StartupViewModel : ReactiveObject, IRoutableViewModel
    {
        private IScreen hostScreen;
        public StartupViewModel(IScreen hostScreen)
        {
            this.hostScreen = hostScreen;
        }
        public string UrlPathSegment => "Startup";
        public IScreen HostScreen => this.hostScreen;

    }
}

后面的代码中没有代码,因为我还没有绑定到视图的属性。

我的代码可以编译,并且我已验证它将成功实例化 MainView 和 MainViewModel。我想找出我哪里出错了。

感谢任何帮助。谢谢!

您需要注册您的视图和视图模型。请看routing example.

在我看来,MainViewModel 构造函数中的这一更改应该可以解决问题:

public MainViewModel()
{
    this.routingState = new RoutingState();

    // register view and viewModel
    Locator.CurrentMutable.Register(() => new StartupView(), typeof(IViewFor<StartupViewModel>));

    routingState.Navigate.Execute(new StartupViewModel(this));
}

@Glenn Watson 提到了一件重要的事情。 Locator 设置应该在 bootstrap-like class 中完成,以允许多平台编码并且不破坏 DI。学基础的时候应该看看这个