Freitag, 20. Dezember 2013

Use MEF to compose objects of types that are unknown at compile time / IoC implementation using MEF

With MEF it is quite easy to create a generic base class that composes objects of a type that is known at compile time.
This was explained in a previous post Generic base class for composing objects with MEF.
This works perfect when the Type is known a compile time. But what if we want to load objects that are defined in a config file? What if we want to create a IoC implementation with MEF where the proper instance is defined in a config file and can be set at runtime. This way the Type is not know at compile time even though the composition relies on knowing the type.
To achieve this there needs to be a ComposablePartCatalog that can compose objects depending on the type.

public class ComposeableTypeCatalog : ComposablePartCatalog
{
    ComposablePartCatalog _catalog;

    public ComposeableTypeCatalog(ComposablePartCatalog catalog)
    {
        _catalog = catalog;
    }

    public override IQueryable<ComposablePartDefinition> Parts
    {
        get { return _catalog.Parts; }
    }

    public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition importDef)
    {
        var result = new List<Tuple<ComposablePartDefinition, ExportDefinition>>();

        // check all parts in that catalog
        foreach (ComposablePartDefinition partDef in Parts)
        {
            // for each part, examine if any export definition matches the requested import definition.
            foreach (ExportDefinition exportDef in partDef.ExportDefinitions)
            {
                // the import has to be made on object
                if(Type.GetType(importDef.ContractName) == typeof(object))
                {
                    var matchingExport = new Tuple<ComposablePartDefinition, ExportDefinition>(partDef, exportDef);                        
                    result.Add(matchingExport);
                }
            }
        }
        return result;
    }
}

In the composition we need to use a TypeCatalog to define the type that should be composed. The big drawback with this approach ist the fact that the Imports have to be made on System.object or IEnumerable<System.object> and not on a concrete type.
public class TypeComposer
{
    private CompositionContainer _container;

    [ImportMany]
    public IEnumerable<object> Imports { get; set; }

    public object Compose(Type type)
    {
        // an aggregate catalog that combines multiple catalogs
        var agregatecatalog = new AggregateCatalog();

        // load only items of type
        agregatecatalog.Catalogs.Add(new TypeCatalog(type));

        // create a catalog that loads the given types into the IEnumerable<object>
        var typecatalog = new ComposeableTypeCatalog(agregatecatalog);

        // create the CompositionContainer with the parts in the catalog
        _container = new CompositionContainer(typecatalog);

        // fill the imports of this object
        try
        {
            _container.ComposeParts(this);
        }
        catch (CompositionException compositionException)
        {
            Console.WriteLine(compositionException.ToString());
        }

        if (Imports == null)
            return null;

        return Imports.FirstOrDefault();
    }
}
This class now imports all objects that are marked with an ExportAttribute containing the type that is passed with the parameter.
[Export(typeof(ComposeableClass))]
public class ComposeableClass
{
}
[TestMethod]
public void TypeComposerTest()
{
    var composer = new TypeComposer();
    var part = composer.Compose(typeof(ComposeableClass));
    Assert.IsNotNull(part as ComposeableClass);
}
As mentioned previously,the big drawback is the fact that the composition is made on System.object and not on the concrete type. This means the object has to be cast into the expected type which can lead to errors.

Donnerstag, 19. Dezember 2013

Generic base class for composing objects using MEF

If MEF is used extensively, it is not practicable to implement the composition for every class or type that has to be compsed. Why not create a generic base class that can load all of the objects that we need.
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

public class Composer<T>
{
    public T Compose<T>()
    {
        Compose();

        if (Imports == null)
            return default(T);

        return (T)(object)Imports.FirstOrDefault();
    }
        
    private static AggregateCatalog _catalog;

    private CompositionContainer _container;

    [ImportMany]
    public IEnumerable<T> Imports { get; set; }

    private void Compose()
    {
        // an aggregate catalog that combines multiple catalogs
        var catalog = new AggregateCatalog();

        // load all assemblies in the current directory
        catalog.Catalogs.Add(new DirectoryCatalog(".", "*.exe"));

        Compose(catalog);
    }

    private void Compose(AggregateCatalog catalog)
    {
        _catalog = catalog;

        // create the CompositionContainer with the parts in the catalog
        _container = new CompositionContainer(_catalog);

        // fill the imports of this object
        try
        {
            _container.ComposeParts(this);
        }
        catch (CompositionException compositionException)
        {
            Console.WriteLine(compositionException.ToString());
        }
    }
}

This class can now be used to Compose objects that are marked with the ExportAtribute.
[Export(typeof(ComposeableClass))]
public class ComposeableClass
{
}
[TestMethod]
public void GenericComposerComposeTest()
{
    var composer = new Composer<ComposeableClass>();
    var part = composer.Compose<ComposeableClass>();
    Assert.IsNotNull(part);
}

Dienstag, 11. Juni 2013

Changing the Image Source property with a trigger

To change the Source of an Image within a Trigger, the Source has to be set in a Style with the help of a Setter. This code won't work because the Trigger can't change/override a Property that has been set outside of the Style.
<Image Source="..\..\Images\OK.png">
    <Image.Style>
        <Style TargetType="{x:Type Image}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding HasError}" Value="True" >
                    <Setter Property="Source" Value="..\..\Images\Error.png"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Image.Style>
</Image>
Remove the Source attribute from the Image tag at the top and add it as a Setter in the Style. This will override whatever is applied by the style. You can move it to another DataTrigger or you can put it in a normal setter like so.
<Image>
    <Image.Style>
        <Style TargetType="{x:Type Image}">
            <Setter Property="Source" Value="..\..\Images\OK.png" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding HasError}" Value="True" >
                    <Setter Property="Source" Value="..\..\Images\Error.png"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Image.Style>
</Image>
This approach can also be used on a TextBlock if the text has to be changed with a Trigger.