如何动态加载 Prism / Composite Application Library 中的模块?

发布于 2024-08-04 20:45:03 字数 2416 浏览 0 评论 0原文

我的 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 (带有邮政编码验证的文本框)

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

ZipCode.dll

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

ZipCodePlus.dll

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

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

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

但是我如何动态实例化它,即将类的名称作为字符串 ,如果该类不存在,那么它将抛出适当的异常,例如:

PSEUDO-CODE:

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

I have a class in my Prism/CAL application which generates a form for users to fill in data.

The form is defined by an XML file like this:

<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>

the form needs to load specific controls which correspond to each field type in the XML, e.g.

  • Title (shows a dropdown: Mr., Mrs., Dr., etc.)
  • Text (simple textbox)
  • Email (textbox with e-mail validation)
  • ZipCode (textbox with zipcode validation)

I want to make each control a separate module which gets loaded so that e.g. the ZipCode module would exist in a Modules directory as a file:

ZipCode.dll

which is just a simple textbox control that validates based on zipcode, but developers could make another control called:

ZipCodePlus.dll

which inherits the same interface but provides a pop-up geo-earth selector for zipcodes. As soon as a customer replaced ZipCode.dll with ZipCodePlus.dll, all of his forms would have this new functionality for searching for zip codes.

However, I'm having trouble visualizing how this will be technically implemented, since as my form class is parsing the XML, it instantiates the classes which provide the functionality for the controls, but in order to instantiate the class, I have to have a reference to it:

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

But how can I instantiate it dynamically, i.e. with the name of the class as a string, and if that class does not exist then it will throw an appropriate exception, e.g. something like this:

PSEUDO-CODE:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

倚栏听风 2024-08-11 20:45:03

看起来您已经非常接近问题的技术解决方案了。我只需创建一个接口 - 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);

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

希望这有帮助!

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

It seems you are very close to a technical solution to your problem. I would simply create an interface - IZipCodePresenter - and in my ZipCode.dll or ZipCodePlus.dll module startup, register the implementation.

Container.RegisterType<IZipCodePresenter, StandardZipCodePresenter>();

Then in your parser, resolve the instance like:

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

Assuming no instances are registered for the interface, an exception will be thrown. Otherwise, you will get the last registered concrete implementation of IZipCodePresenter. Note that an exception will only be thrown if you try and register an interface. If you attempt to register a class with Unity, it will create an instance based on the Lifetime Manager policy.

If you wanted to go further with this, you could create an interface... something like IDynamicPresenter. You could then register based on a known string (defined in your infrastructure project).

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

and then resolve like the following:

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

I prefer the former solution, but this is certainly a valid option.

Hope this helps!

P.s. This sounds like an interesting idea... I'd be interested to hear how you get on with the implementation. You could even move one step further and create a whole XAML builder framework based on some of the concepts in ASP.NET MVC. It could facilitate ease in testing, yet have the power of WPF. Good luck!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文