【问题标题】:How to dynamically load modules in Prism / Composite Application Library?如何在 Prism / Composite Application Library 中动态加载模块?
【发布时间】:2009-09-14 09:34:14
【问题描述】:

我的 Prism/CAL 应用程序中有一个,它生成一个表单供用户填写数据。

表单由 XML 文件定义,如下所示:

<area idCode="general" title="General">
    <column>
        <group title="Customer Data">
            <field idCode="title" requiredStatus="true">
                <label>title</label>
                <fieldType>Title</fieldType>
            </field>
            <field idCode="firstName" requiredStatus="true">
                <label>First Name</label>
                <fieldType>Text</fieldType>
            </field>
            <field idCode="lastName" requiredStatus="true">
                <label>Last Name</label>
                <fieldType>Text</fieldType>
            </field>
            <field idCode="email" requiredStatus="true">
                <label>E-Mail</label>
                <fieldType>Email</fieldType>
            </field>
            ...
        </group>
        </column>
    </area>

表单需要加载特定的控件,这些控件对应于XML中的每个字段类型,例如

  • 职称(显示下拉菜单:先生、夫人、博士等)
  • 文本(简单文本框)
  • 电子邮件(带有电子邮件验证的文本框)
  • 邮政编码(带有邮政编码验证的文本框)

我想让每个控件成为一个单独的模块,以便加载,例如ZipCode 模块将作为文件存在于 Modules 目录中:

ZipCode.dll

这只是一个基于邮政编码验证的简单文本框控件,但开发人员可以制作另一个控件,称为:

ZipCodePlus.dll

继承了相同的界面,但提供了一个用于邮政编码的弹出式地理地球选择器。一旦客户将 ZipCode.dll 替换为 ZipCodePlus.dll,他的所有表单都将具有此 功能 用于搜索邮政编码。

但是,我无法想象这将如何在技术上实现,因为当我的表单类解析 XML 时,它会实例化为控件提供功能的类,但为了实例化 类,我必须对它有一个reference

SmartFormFieldZipCodePresenter smartFormFieldEmailPresenter
    = container.Resolve<SmartFormFieldEmailPresenter>();

但是我如何动态地实例化它,即使用类的名称作为字符串,如果该类不存在,那么它会抛出一个适当的异常,例如像这样:

伪代码:

try {
    var smartFormFieldZipCodePresenter
        = container.Resolve("smartFormFieldZipCodePresenter");
}
catch (ModuleDoesNotExistException) {
    ...
}

【问题讨论】:

  • 您使用的是哪种解析器。是延迟加载还是急切加载。我们也在使用类似的方法。

标签: c# wpf dependency-injection unity-container prism


【解决方案1】:

您似乎非常接近解决问题的技术方案。我只需创建一个接口 - IZipCodePresenter - 然后在我的 ZipCode.dll 或 ZipCodePlus.dll 模块启动中注册实现。

Container.RegisterType<IZipCodePresenter, StandardZipCodePresenter>();

然后在你的解析器中,像这样解析实例:

var zipCodePresenter = container.Resolve<IZipCodePresenter>();

假设没有为接口注册实例,则会抛出异常。否则,您将获得最后注册的 IZipCodePresenter 的具体实现。请注意,仅当您尝试注册接口时才会引发异常。如果您尝试向 Unity 注册一个类,它将根据 Lifetime Manager 策略创建一个实例。

如果您想更进一步,您可以创建一个界面...类似于 IDynamicPresenter。然后,您可以根据已知字符串(在您的基础设施项目中定义)进行注册。

Container.RegisterType<IDynamicPresenter, StandardZipCodePresenter>(PresenterName.ZipCodeControl);
Container.RegisterType<IDynamicPresenter, StandardEmailPresenter>(PresenterName.EmailControl);

然后像下面这样解决:

var zipCodeControl = Container.Resolve<IDynamicPresenter>(PresenterName.ZipCodeControl);
var emailControl = Container.Resolve<IDynamicPresenter>(PresenterName.EmailControl);

我更喜欢前一种解决方案,但这当然是一个有效的选择。

希望这会有所帮助!

附:这听起来像是一个有趣的想法......我很想听听您如何继续实施。您甚至可以更进一步,基于 ASP.NET MVC 中的一些概念创建一个完整的 XAML 构建器框架。它可以简化测试,但具有 WPF 的功能。祝你好运!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-26
    相关资源
    最近更新 更多