通过作用域RegionManager的Region将视图添加到ItemsControl的ItemsSource



我正试图通过区域填充ComboBox(ItemsControl的衍生物)的ItemsSource

查看

作用域RegionManager(位于视图模型上)通过prism:RegionManager.RegionManager="{Binding RegionManager}"分配给视图。

主窗口.xam

<Window x:Class="Applications.Testing.Wpf.RegionCreationTester.MainWindow"
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:Applications.Testing.Wpf.RegionCreationTester"
xmlns:prism="http://www.codeplex.com/prism"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
prism:RegionManager.RegionManager="{Binding RegionManager}"
prism:ViewModelLocator.AutoWireViewModel="True">
<Grid>
<ComboBox prism:RegionManager.RegionName="{x:Static local:RegionNames.itemsControlRegion}"/>
</Grid>
</Window>

主窗口.xaml.cs

namespace Applications.Testing.Wpf.RegionCreationTester
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, IModelled<MainWindowViewModel>
{
public MainWindowViewModel ViewModel
{
get
{
return (MainWindowViewModel)DataContext;
}
set
{
DataContext = value;
}
}
public MainWindow()
{
InitializeComponent();
ViewModel.PopulateItemsControl();
}
}
}

ViewModel

视图模型通过prism:ViewModelLocator.AutoWireViewModel="True"分配给视图的DataContext。

MainWindowViewModel.cs

namespace Applications.Testing.Wpf.RegionCreationTester
{
public class MainWindowViewModel
{
/// <summary>
/// Gets the <see cref="RegionManager"/> scoped to this control.
/// </summary>
/// <remarks>Exists so that child controls can register regions for their own child controls which are also child controls in this control.</remarks>
public RegionManager RegionManager { get; } = new RegionManager();
/// <summary>
/// Adds some child views to the <see cref="RegionNames.itemsControlRegion"/>.
/// </summary>
/// <remarks>Normally these views would be resolved using an IoC container but this have been omitted for brevity.</remarks>
public void PopulateItemsControl()
{
var region = RegionManager.Regions[RegionNames.itemsControlRegion];
region.Add(new TextBlock { Text = "Item #1" });
region.Add(new Button { Content = "Item #2" });
}
}
}

RegionNames.cs

namespace Applications.Testing.Wpf.RegionCreationTester
{
public static class RegionNames
{
public const string itemsControlRegion = "collectionRegion";
}
}

引导程序

应用程序xaml

<Application x:Class="Applications.Testing.Wpf.RegionCreationTester.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"/>

App.xaml.cs

namespace Applications.Testing.Wpf.RegionCreationTester
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
new RegionCreationTesterBootstrapper().Run();
}
}
}

RegionCreationTesterBootstrapper.cs

namespace Applications.Testing.Wpf.RegionCreationTester
{
public class RegionCreationTesterBootstrapper : UnityBootstrapper
{
protected override DependencyObject CreateShell()
=> new MainWindow();
protected override void InitializeShell()
{
base.InitializeShell();
(Application.Current.MainWindow = (Window)Shell).Show();
}
}
}

一旦发生了所有区域填充并且应用程序即将运行,我就会在new RegionCreationTesterBootstrapper().Run()App中得到一个包含InnerException的Prism.Regions.UpdateRegionsException,消息为"Region with the given name is already registered: collectionRegion"。在我的代码中,我能够获得断点命中的最后一行是在对MainWindow的构造函数的调用退出后,CreateShell中的new MainWindow()。为什么我只想注册一次,却被告知该地区已经注册?我在MainWindow的构造函数中设置了断点,以确认它只创建过一次,即使没有,它所作用域的RegionManager也应该防止此异常发生。我错过了什么?

更新

我刚刚注释掉了PopulateItemsControl中的代码,发现即使只有一个视图被添加到区域中,也会抛出异常,更奇怪的是,如果没有向区域添加视图,但访问了区域(如第var region = RegionManager.Regions[RegionNames.itemsControlRegion];行中所做的)。因此,现在的问题是访问作用域RegionManager上的现有区域进行视图注入,以便向其中添加视图;我不知道为什么从RegionManager访问一个区域会改变它的状态,这似乎是Prism中的一个错误,或者可能与懒惰枚举有关。

好吧,你已经做了两次了,只是你没有意识到。当您在ComboBox上设置RegionName附加属性时,将附加一个将创建具有给定名称的区域的事件hanler(这是RegionManager的静态部分)。当您在VM中实例化的RegionManager的实例尝试访问区域集合时,索引器首先在RegionManager类上调用引发事件的静态方法。获得创建区域任务的全局RegionManager实例(当您使用RegionName附加的属性时)尚未完成它的作业-当您尝试使用实例访问区域时,尚未加载该窗口,处理程序尚未删除,并且会再次调用它。如果在窗口加载后调用PopulateItemsControl方法(比如在MainWindow的loaded事件处理程序中),则不会得到异常,但代码将无法按预期工作。这是因为您的CCD_;处理";您的收藏区域,全球RegionManager是.

正在注入RegionManager实例

如果您的VM中需要RegionManager实例,请使用构造函数注入。

public class MainWindowViewModel : BindableBase
{
private IRegionManager rm;
public MainWindowViewModel(IRegionManager manager)
{
this.rm = manager;
}
public void PopulateItemsControl()
{
var region = rm.Regions[RegionNames.itemsControlRegion];
region.Add(new TextBlock { Text = "Item #1" });
}
}

依赖注入容器(Unity或您正在使用的任何容器)将在创建VM时解析IRegionManager实例(PRISM无论如何都在为您做这项工作,您不是自己实例化它)。

区域范围

CCD_ 27保留区域的集合,并且不允许具有相同名称的区域。因此,除非您的窗口将有多个ComboBoxes,它们都有一个名为collectionRegion的区域,否则RegionManager(全局区域)是可以的。如果您的collectionRegion将具有相同视图类的实例,这些实例都在自己内部定义了另一个区域,那么您需要区域作用域——RegionManager实例具有自己的视图作用域。在这种情况下,Add方法可以为该视图创建RegionManager的本地实例:

IRegion collectionRegion = this.regionManager.Regions["collectionRegion"];
bool makeRegionManagerScope = true;
IRegionManager localRegionManager =
collectionRegion.Add(view, null, makeRegionManagerScope);

相关内容

  • 没有找到相关文章

最新更新