Coproject – demo RIA aplikace krok za krokem, díl 5.
V tomto díle použijeme metadata pro upřesnění modulů. Nezapomeňte, že zdrojové kódy Coprojectu si můžete stáhnout z Codeplexu.
Metadata
Jistě jste si povšimli, že moduly se v aplikaci nezobrazují v pevně daném pořadí. To není přesně to, co bychom od aplikace očekávali, bude tedy nutné specifikovat pořadí modulů. K tomu využijeme metadata. Více o metadatech v MEFu si můžete přečíst zde.
Nejsnazší možností, jak přidat metadata k exportovaným komponentám, je použít atribut [ExportMetadata]. S ním by upravený HomeViewModel vypadal následovně:
[Export(typeof(IModule))] [ExportMetadata("Order", 10)] public class HomeViewModel : Screen, IModule
Ostatní moduly se pak liší jen v čísle Order. Dále je nutné upravit konstruktor ShellViewModelu, aby místo kolekce objektů IModule očekával kolekci typů Lazy<IModule, IModuleMetadata>. Tím MEF dodá nejenom referenci na požadovanou komponentu (v tomto případě navíc “Lazy” způsobem, tj. vlastní instance se vytvoří až poté, co je odkaz poprvé opravdu využit), ale také metadata. Více o typu Lazy si můžete přečíst zde.
Pojďme tedy vytvořit metadata – do nové složky /Framework/ přidejte interface IModuleMetadata:
namespace Coproject.Framework { public interface IModuleMetadata { int Order { get; } } }
Teď už můžeme upravit i zmíněný konstruktor v ShellViewModelu:
[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); }
To je vše – spusťte aplikaci. Můžete zkoušet měnit čísla Order u jednotlivých modulů a sledovat, jak se podle toho mění jejich pořadí v hlavní menu aplikace.
Typovaná metadata
Ačkoliv výše zmíněné řešení splňuje to, co od něj požadujeme, je možné, že stejně jako já nemáte rádi textové konstanty přímo v kódu (“Order”). Při psaní se člověk může často překlepnout a tyto chyby se pak velice obtížně odhalují. Ideální by tedy bylo, aby se případný překlep objevil již při kompilaci. K tomu si budeme muset napsat vlastní atribut pro exportní metadata. Do složky Framework přidejte novou třídu “ExportModuleAttribute”. Projekt by teď měl vypadat takto:
Implementace nové třídy bude následující:
[MetadataAttribute] [AttributeUsage(AttributeTargets.Class)] public class ExportModuleAttribute : ExportAttribute, IModuleMetadata { public int Order { get; private set; } public ExportModuleAttribute(int order) : base(typeof(IModule)) { Order = order; } }
Jak vidíte, rozšířili jsme původní atribut [Export] o property Order. Jelikož se tento atribut bude používat pouze na moduly, můžeme v konstruktoru hned upřesnit, že budeme exportovat interface IModule. Důležitý je první řádek, který MEFu říká, že z tohoto atributu si má také vytáhnout doplňující metadata k exportu.
Nyní už můžeme původní řádky označující moduly:
[Export(typeof(IModule))] [ExportMetadata("Order", 10)]
Nahradit tímto:
[ExportModule(10)] public class HomeViewModel : Screen, IModule
Upravte takto všechny moduly a zkuste spustit Coproject.
PartCreationPolicy
Když už mluvíme o MEFu, jistě vás zajímá, jak se MEF zachová, když je jedna komponenta importována na více místech – bude vždycky vytvořena nová instance, nebo všichni “obdrží” tu stejnou? Odpověď není jednoznačná, záleží to totiž na konfiguraci. Tato konfigurace může proběhnout na dvou místech: buď u exportu
[ExportModule(10)] [PartCreationPolicy(CreationPolicy.NonShared)] public class HomeViewModel : Screen, IModule
nebo u importu
[Import(typeof(IShell), RequiredCreationPolicy=CreationPolicy.Shared)] public IShell Shell { get; set; }
CreationPolicy může nabývat tří hodnot:
Shared – MEF vrátí vždy stejnou instanci (tudíž se komponenta chová jako singleton)
NonShared – MEF vždy vytvoří pro každý import novou instanci
Any – není definováno, záleží na druhém konci kontraktu (export/import). Toto je výchozí nastavení a pokud není specifikováno ani na jedné straně kontraktu, chová se jako Shared.
Více se o tomto tématu můžete dočíst zde. Pokud vás MEF zaujal, rozhodně doporučuji přečíst tyto stránky: MEF for Beginner a MEF Programming Guide.
Komentáře