Wpf Prism/MEF:如何在不硬编码区域名称的情况下注册ServiceWithRegion

Wpf Prism/MEF:如何在不硬编码区域名称的情况下注册ServiceWithRegion,wpf,module,region,prism-4,Wpf,Module,Region,Prism 4,我们正在构建一个WPF Prism应用程序。我们有不同的开发人员处理不同的模块项目,多个模块被注入到主应用程序外壳中。主要应用程序也是一个单独的项目。我们还希望能够在不同的应用程序中使用这些模块。我们不希望在每个应用程序中都使用相同的名称命名区域 例如,假设我们有一个用于两个不同应用程序的模块。在一个应用程序中,其开发人员可以将模块的区域命名为“DetailsRegion”,而在另一个应用程序中,其开发人员可以将其命名为“ResultsRegion” 我可以找到的每个示例都通过在模块的类定义中硬

我们正在构建一个WPF Prism应用程序。我们有不同的开发人员处理不同的模块项目,多个模块被注入到主应用程序外壳中。主要应用程序也是一个单独的项目。我们还希望能够在不同的应用程序中使用这些模块。我们不希望在每个应用程序中都使用相同的名称命名区域

例如,假设我们有一个用于两个不同应用程序的模块。在一个应用程序中,其开发人员可以将模块的区域命名为“DetailsRegion”,而在另一个应用程序中,其开发人员可以将其命名为“ResultsRegion”

我可以找到的每个示例都通过在模块的类定义中硬编码区域名称来将视图注册到区域:

我要做的是将区域名称放在主应用程序的app.config文件中,并将该名称传递给模块。大概是这样的:

在主Shell应用程序的app.config中:

<Modules>
   <SearchModule>
       <add key="RegionName" value="SearchRegion" />
    </SearchModule>
</Modules>
在某种程度上,这将是将模块与外壳以及彼此完全解耦的最后一步

这在模块的视图中非常有效。但我无法在模块的类定义文件中执行此操作,因为ConfigurationManager在该级别不可用

我可以通过将区域名称放在模块app.config的applicationSettings部分来实现这一点。但这违背了将模块存储在一个位置以供多个应用程序加载的目的。它确实需要位于主应用程序的app.config中


是否有一种方法可以将模块视图注册到区域,而不必在代码中硬编码区域名称?我们尽了最大努力不去硬编码任何东西。这里真的有必要吗?

正如Meleak在他的评论中提到的:使用静态类

namespace Infrastructure
{
    public static class RegionNames
    {
        public const string MainRegion = "MainRegion";
    }
}
在xaml代码中,可以使用区域名称,如下所示:

<UserControl 
    xmlns:Inf="clr-namespace:Infrastructure;assembly=Infrastructure"
    xmlns:Regions="clr-namespace:Microsoft.Practices.Prism.Regions;assembly=Microsoft.Practices.Prism">
    <ContentControl Regions:RegionManager.RegionName="{x:Static Inf:RegionNames.MainRegion}"/>
</UserControl>

我明白了。事实证明我在一点上错了,我为此道歉。父应用程序的.config设置在模块类定义级别可用。必须添加正确的引用并进行正确的导入(或使用)条目。我一定是在键盘前打盹

在主机应用程序的
app.config中,添加configSection定义。在这里,我定义了两个模块的部分:

<configSections>
    <sectionGroup name="Modules">
        <section name="SearchModule" type="System.Configuration.NameValueSectionHandler" />
        <section name="HeaderModule" type="System.Configuration.NameValueSectionHandler"/>
    </sectionGroup>
   ...
</configSections>
在模块的类定义文件的初始化方法中:

VB:
    Public Sub Initialize() Implements Microsoft.Practices.Prism.Modularity.IModule.Initialize
        Dim settings As NameValueCollection = CType(ConfigurationManager.GetSection("Modules/SearchModule"), NameValueCollection)
        MyRegionManager.RegisterViewWithRegion(settings("Region"), GetType(SearchModuleView))
    End Sub

C#:
    public void Initialize() : Microsoft.Practices.Prism.Modularity.IModule.Initialize
    {
        (NameValueCollection)settings = (NameValueCollection)ConfigurationManager.GetSection("Modules/SearchModule");
        MyRegionManager.RegisterViewWithRegion(settings["Region"], typeof(SearchModuleView));
    }
然后,这将根据宿主应用程序的app.config中的条目向区域注册视图。这意味着可以为多个主机应用程序构建一个模块,并且可以将其插入主机中任何名称的区域。无需在编译代码中进行更改,也无需为每个应用程序创建单独的RegionNames类

我们的应用程序也是使用MVVM架构构建的。我们在宿主应用程序中定义视图模型,并通过使用RegionContext或EventAggregator在app.config中定义的名称将它们公开给模块。这将使模块与应用程序完全解耦,并使模块在不同的应用程序中完全可重用,无需修改


感谢您的输入,我希望这对以后的其他人有所帮助。

我看到的大多数示例都将区域名称作为一组静态字符串放在基础结构类库中名为RegionNames的静态类中,这也是我们正在做的。这些静态字符串用于shell和模块中。也许您可以为每个应用程序使用不同的RegionNames文件。我应该提到,我们确实有一个基础结构类库,其中包含所有模块和所有应用程序共享的代码。因此,每个应用程序的静态RegionNames类并不是真正的答案。仍然必须在应用程序中编译静态类。这只是硬编码区域名称的另一种方式。我希望能够将区域名称放在基本应用程序级别的.config文件中,而不需要与应用程序一起编译。谢谢。但请看我对Meleak的评论。在C#code:Initialize()中,只是一个指针:Microsoft.Practices.Prism.Modularity.IModule.Initialize应该删除冒号后的所有内容。在C#中,我们不需要那个愚蠢的部分,因为如果名称和签名匹配,就足够了。这是人们对VB的一大抱怨!
<configSections>
    <sectionGroup name="Modules">
        <section name="SearchModule" type="System.Configuration.NameValueSectionHandler" />
        <section name="HeaderModule" type="System.Configuration.NameValueSectionHandler"/>
    </sectionGroup>
   ...
</configSections>
<Modules>
    <SearchModule>
        <add key="Region" value="SearchRegion"/>
    </SearchModule>
    <HeaderModule>
        <add key="Region" value="HeaderRegion"/>
    </HeaderModule>
</Modules>
VB:
Imports System.Collections.Specialized
Imports System.Configuration

C#:
using System.Collections.Specialized;
using System.Configuration;
VB:
    Public Sub Initialize() Implements Microsoft.Practices.Prism.Modularity.IModule.Initialize
        Dim settings As NameValueCollection = CType(ConfigurationManager.GetSection("Modules/SearchModule"), NameValueCollection)
        MyRegionManager.RegisterViewWithRegion(settings("Region"), GetType(SearchModuleView))
    End Sub

C#:
    public void Initialize() : Microsoft.Practices.Prism.Modularity.IModule.Initialize
    {
        (NameValueCollection)settings = (NameValueCollection)ConfigurationManager.GetSection("Modules/SearchModule");
        MyRegionManager.RegisterViewWithRegion(settings["Region"], typeof(SearchModuleView));
    }