如何在 PRISM 模块中使用 ReactiveUI
How to use ReactiveUI inside a PRISM module
我们有一个现有的 WPF 应用程序,它使用 PRISM (6.x) 和 Unity (3.5.x) 进行 DI。我们将向该应用程序添加更多功能,并希望开始将 ReactiveUI 用于我们需要实现的任何新模块。
我们希望最大限度地减少学习曲线,并继续为我们的 ViewModels 使用 Unity 和 DI;但是,ReactiveUI 使用 Splat 作为视图位置,到目前为止,无论我尝试了什么,我都无法让我的 ReactiveUI 模块实际显示在我们主应用程序的 PRISM 区域中。
我真正找到的唯一一篇文章是这篇 post Issues with IMutableDependencyResolver and Structuremap in ReactiveUI,其中有人正在编写他们自己的集成。
所以给定一些 ViewModel:
public class HelloWorldViewModel : ReactiveObject
{
string title = "Hello ReactiveUI";
public string Title
{
get { return title; }
set { this.RaiseAndSetIfChanged(ref title, value); }
}
}
及其对应的视图:
<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 初始化中需要什么来连接 ReactiveUI ViewModel 和 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">
我也试过在模块的初始化中初始化 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 和 RxUI 以及视图绑定的不同语义。
Prism 尝试为给定视图解析 VM 类型,而 RxUI 则相反,为当前 VM 解析视图。
您的实施(几乎)有效:
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 覆盖实例 created/set(这是你的问题我相信)。
简单地删除这个绑定是可行的,但总的来说,它似乎不是混合 Prism 和 RxUI 的好方法。
也许您可以查看 RxUI RoutedViewHost
和 ViewModelViewHost
并将其中之一绑定到该区域。然后 RxUI 视图解析将自动启动,并根据控件上设置的当前 VM 刷新内部视图。这是您需要像您一样注册您的观点的时候:
Locator.CurrentMutable.Register(() => new HelloWorldView(), typeof(IViewFor<HelloWorldViewModel>));
我们有一个现有的 WPF 应用程序,它使用 PRISM (6.x) 和 Unity (3.5.x) 进行 DI。我们将向该应用程序添加更多功能,并希望开始将 ReactiveUI 用于我们需要实现的任何新模块。
我们希望最大限度地减少学习曲线,并继续为我们的 ViewModels 使用 Unity 和 DI;但是,ReactiveUI 使用 Splat 作为视图位置,到目前为止,无论我尝试了什么,我都无法让我的 ReactiveUI 模块实际显示在我们主应用程序的 PRISM 区域中。
我真正找到的唯一一篇文章是这篇 post Issues with IMutableDependencyResolver and Structuremap in ReactiveUI,其中有人正在编写他们自己的集成。
所以给定一些 ViewModel:
public class HelloWorldViewModel : ReactiveObject
{
string title = "Hello ReactiveUI";
public string Title
{
get { return title; }
set { this.RaiseAndSetIfChanged(ref title, value); }
}
}
及其对应的视图:
<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 初始化中需要什么来连接 ReactiveUI ViewModel 和 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">
我也试过在模块的初始化中初始化 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 和 RxUI 以及视图绑定的不同语义。
Prism 尝试为给定视图解析 VM 类型,而 RxUI 则相反,为当前 VM 解析视图。
您的实施(几乎)有效:
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 覆盖实例 created/set(这是你的问题我相信)。
简单地删除这个绑定是可行的,但总的来说,它似乎不是混合 Prism 和 RxUI 的好方法。
也许您可以查看 RxUI RoutedViewHost
和 ViewModelViewHost
并将其中之一绑定到该区域。然后 RxUI 视图解析将自动启动,并根据控件上设置的当前 VM 刷新内部视图。这是您需要像您一样注册您的观点的时候:
Locator.CurrentMutable.Register(() => new HelloWorldView(), typeof(IViewFor<HelloWorldViewModel>));