您的位置:首页 > 运维架构

Coproject - a RIA Caliburn.Micro demo, part 5

2015-09-03 06:49 381 查看
In this part, we will add some module metadata. Note that you can get the most recent Coproject source codes from itsCodeplex site.


Metadata

As you probably noticed, modules are not loaded into shell in any specified order. And since we don’t want the modules be in arbitrary order, we need to add some metadata. You can read more about MEF metadata here.

The easiest way is to use ExportMetadataAttribute. We would update HomeViewModel as:
[Export(typeof(IModule))]
[ExportMetadata("Order", 10)]
public class HomeViewModel : Screen, IModule


and the other ViewModels in the same manner. Next, must update ShellViewModel constructor. Instead of IModule directly, we will request Lazy<IModule, IModuleMetadata> from MEF. This will make MEF to provide lazy reference to requested instance and also metadata
of type IModuleMetadata. You might read an introduction to Lazy here.

Let’s create IModuleMetadata in new folder /Framework/:
namespace Coproject.Framework
{
        public interface IModuleMetadata
        {
                int Order { get; }
        }
}


Finally, ShellViewModel’s constructor:
[ImportingConstructor]
public ShellViewModel([ImportMany]IEnumerable<Lazy<IModule, IModuleMetadata>> moduleHandles)
{
        var modules = from h in moduleHandles orderby h.Metadata.Order select h.Value;
        Items.AddRange(modules);
}


The code should be self-describing. Now, run the application. You may experiment with order numbers and see that the order in application menu changes respectively.


Strongly typed metadata

Although this solution works, you probably don’t like the idea of writing magic strings like “Order”. So we should make these metadata strongly typed. To do this, add new class ExportModuleAttribute to the Framework folder. Application structure should look
like this:




Add this implementation of the created class:
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class)]
public class ExportModuleAttribute : ExportAttribute, IModuleMetadata
{
        public int Order { get; private set; }

        public ExportModuleAttribute(int order)
                : base(typeof(IModule))
        {
                Order = order;
        }
}


As you can see, we simply extend the original ExportAttribute to accept order integer. In this case, we can add default export type (IModule). The first attribute [MetadataAttribute] is very important because it tells MEF to also load metadata from ExportModuleAttribute.
Finally, we can merge the two attributes on each module viewmodel:
[Export(typeof(IModule))]
[ExportMetadata("Order", 10)]


into one:
[ExportModule(10)]
public class HomeViewModel : Screen, IModule


Do this for all module view models and run the application.


PartCreationPolicy

Talking about MEF exports, you might wonder what happens when you import a component more than once – will MEF provide you the same instance or will it create a new one? The answer is: It depends on configuration. You can specify this behavior on the places.
Either on export:
[ExportModule(10)]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeViewModel : Screen, IModule


Or on import:
[Import(typeof(IShell), RequiredCreationPolicy=CreationPolicy.Shared)]
public IShell Shell { get; set; }


CreationPolicy enum has three options:
Shared – MEF will return always the same instance (singleton pattern)
NonShared – MEF will always create a new instance
Any – not specified, depends on the other side of contract (export/import). This is default and if not set to other, this will act as Shared by default.

You can read more about this topic here. I suggest reading whole series MEF
for Beginner or MEF Programming Guide.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: