如何在PRISM模块中使用ReactiveUI

本文关键字:ReactiveUI 模块 PRISM | 更新日期: 2023-09-27 18:16:03

我们有一个现有的WPF应用程序,它使用PRISM (6.x)和Unity (3.5.x)作为DI。我们将为这个应用程序添加更多的功能,并希望开始为我们需要实现的任何新模块使用ReactiveUI。

我们希望最小化学习曲线,并继续使用Unity和DI为我们的ViewModels;然而,ReactiveUI使用Splat作为视图位置,到目前为止,无论我尝试了什么,我都无法让我的ReactiveUI模块在主应用程序中的PRISM区域中实际显示。

我真正发现的唯一一篇文章是这篇文章IMutableDependencyResolver和Structuremap在ReactiveUI的问题,有人在写他们自己的集成。

给定ViewModel:

public class HelloWorldViewModel : ReactiveObject 
{
    string title = "Hello ReactiveUI";
    public string Title
    {
        get { return title; }
        set { this.RaiseAndSetIfChanged(ref title, value); }
    }
}

及其对应的View:

<UserControl x:Class="PBI.ObjectMover.ReactSample.Views.HelloWorldView"
         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">
  <Grid>
    <TextBlock Text="{Binding Title}" Foreground="Green" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Calibri" FontSize="24" FontWeight="Bold"></TextBlock>            
  </Grid>
</UserControl>

以及视图实现IViewFor<T>接口背后的代码:

public partial class HelloWorldView : UserControl, IViewFor<HelloWorldViewModel>
{
    public HelloWorldView()
    {
        InitializeComponent();
        this.WhenAnyValue(x => x.ViewModel).BindTo(this, x => x.DataContext);
    }
    public HelloWorldViewModel ViewModel
    {
        get { return (HelloWorldViewModel)GetValue(ViewModelProperty); }
        set { SetValue(ViewModelProperty, value); }
    }
    public static readonly DependencyProperty ViewModelProperty =
        DependencyProperty.Register("ViewModel", typeof(HelloWorldViewModel), typeof(HelloWorldView), new PropertyMetadata(null));
    object IViewFor.ViewModel { get; set; }
}
在IModule初始化中需要什么来使reactiveuiviewmodel和View连接起来?
public class ReactSampleModule : IModule
{
    private readonly IRegionManager RegionManager;
    public ReactSampleModule(IUnityContainer container, IRegionManager regionManager)
    {
        this.RegionManager = regionManager;
    }
    public void Initialize()
    {
        /* What do I need here to initialize ReactiveUI or Unity? */
        /* Register views */
        this.RegionManager.RegisterViewWithRegion("RightRegion", typeof(HelloWorldView)); 
    }
}

我已经尝试添加棱镜定位器到视图的XAML:

<UserControl x:Class="PBI.ObjectMover.ReactSample.Views.HelloWorldView"
         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:prism="http://prismlibrary.com/"
         prism:ViewModelLocator.AutoWireViewModel="True">

我还尝试在模块的initialize中初始化Splat:

    public void Initialize()
    {
        /* Register types */
        Locator.CurrentMutable.InitializeSplat();
        Locator.CurrentMutable.InitializeReactiveUI();
        Locator.CurrentMutable.Register(() => new HelloWorldView(), typeof(IViewFor<HelloWorldViewModel>));
        /* Register views */
        this.RegionManager.RegisterViewWithRegion("RightRegion", typeof(HelloWorldView)); 
    }

到目前为止,没有任何工作,但我怀疑我们是唯一看到使用PRISM的模块化架构与ReactiveUI的框架的好处的人。

如何在PRISM模块中使用ReactiveUI

Prism和RxUI以及不同的视图绑定语义

Prism尝试为给定的视图解析VM类型,而RxUI则相反,为当前VM解析view。

你的实现(几乎)工作了:

this.RegionManager.RegisterViewWithRegion("RightRegion", typeof(HelloWorldView));

这足以显示视图,如果您添加AutoWireViewModel=True, Prism将创建一个VM实例并将其设置为您的视图DataContext

注意这一行:

this.WhenAnyValue(x => x.ViewModel).BindTo(this, x => x.DataContext);

尝试将ViewModel属性绑定到相同的DataContext,并且将愉快地使用null这样做,覆盖Prism创建/设置的实例(我相信这是您的问题)。

简单地删除这个绑定工作,但总的来说,它似乎不是一个很好的方式来混合Prism和RxUI。

也许你可以查看RxUI RoutedViewHostViewModelViewHost,并将其中一个绑定到该区域。然后RxUI视图解析将自动启动,并根据控件上的当前VM集刷新内部视图。这是你需要注册视图的时候,就像你所做的那样:

Locator.CurrentMutable.Register(() => new HelloWorldView(), typeof(IViewFor<HelloWorldViewModel>));