Skip to content

biohazard999/Para.FluentModelBuilder

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 

Para.FluentModelBuilder

Fluent Model Builder for the DevExpress.ExpressApp Framework

Don't like polution of your XPO/EntityFramework assembly with XAF Attributes?

We have a solution:

Use flutent syntax to assign attributes to your existing XPO code.

Inspired by EntityFramework it can provide the metadata and attributes required by the XAF-Framework.

But How?

Based on the Fluent-Interface-Pattern it will cure the problem of dealing with String-Magic in Attributes for Criterias, PropertyNames and other ugly stuff in your ModelCode.

Show me, Show me!

For our UnitTest Project we have this simple classes:

class TargetClass
{
	internal const string StringProperty_PropertyName = "StringProperty";

	internal const string StringProperty_Format = "{0:" + StringProperty_PropertyName + "}";

	internal string StringProperty { get; set; }

	internal DateTime DateTimeProperty { get; set; }

	internal DateTime? NullableDateTimeProperty { get; set; }

	internal ReferencedTargetClass OneToReferencedTarget { get; set; }
}

class ReferencedTargetClass
{
	public string Prop { get; set; }
}

Don't be afraid, that it is not a XPO/EF class, but it will be recognized by the excelent typesystem of XAF (ITypesInfo, ITypeInfo, IMemberInfo, ect.)

For XAF we can capsulate the mapping in a derived class called XafBuilderManager:

class TestXafModelBuilderManager : XafBuilderManager
{
	public TestXafModelBuilderManager(ITypesInfo typesInfo) : base(typesInfo)
	{
	}
    
	public override IEnumerable<IBuilder> BuildUpModel(ITypesInfo typesInfo)
	{
		yield return new TargetClassBuilder(typesInfo);

		var builder2 = ModelBuilder.Create<ReferencedTargetClass>(typesInfo);

		builder2.For(m => m.Prop)
			.HasCaption("Test");

		yield return builder2;
	}
}

As you can see here we have 2 options to map our classes: as a seperate class derived from ModelBuilder<T> called TargetClassBuilder in this example, or map all the stuff in this class, with the fluent interface.

class TargetClassBuilder : ModelBuilder<TargetClass>
{
	public TargetClassBuilder(ITypesInfo typesInfo) : base(typesInfo)
	{
	}

	public TargetClassBuilder(ITypeInfo typeInfo) : base(typeInfo)
	{
	}

	protected override void BuildUp()
	{
		HasCaption("Test");

		For(m => m.DateTimeProperty)
			.HasCaption("Date")
			.HasDisplayFormat("{0:dd.mm.yyyy")
			.IsImmediatePostData()
			.IsVisibleInDetailView()
			.IsNotVisibleInLookupListView()

		.UsingAppearance()
			.Targeting(m => m.StringProperty)
				.When(CriteriaOperator.Parse("DateTimeProperty == @Today()"))
				.IsNotEnabled()
				.HavingPriority(99);

		For(m => m.StringProperty)
			.AllowingDelete()
			.HasCaption("Bla");

		For(m => m.StringProperty)
			.UsingAppearance()
				.When("StringProperty == 'foo'")
				.TargetingAll()
				.ExceptingTarget(m => m.NullableDateTimeProperty);
	}
}

How do i tell XAF to use this?

Basically everything is there from the XAF-Team. We have this little method in our Modules we can override called CustomizeTypesInfo. Everything we need to do is to let the magic begin and call our constructor:

public sealed partial class TestModule : ModuleBase
{
    public override void CustomizeTypesInfo(ITypesInfo typesInfo)
    {
        base.CustomizeTypesInfo(typesInfo);
        new TestXafModelBuilderManager(typesInfo);
    }
}

Cool, but what about our own Attributes?

Thats a great question:

There are 2 possible solutions:

Use ModelBuilder<T>.WithAttribute(Attribute attribute) or ModelBuilder<T>.WithAttribute<TAttribute>(Action<TAttribute> attributeOptions).

For(m => m.StringProperty)
	.WithAttribute(new YourProperty("whatever"));

Or:

Write a new Extention-Method that adds syntactic sugar to the whole thing (ConditionalAppearance is realized with this):

public static class ConditionalAppearancePropertyBuilder
{
    public static ConditionalAppearancePropertyBuilder<TProp, T> UsingAppearance<TProp, T>(this PropertyBuilder<TProp, T> builder, string shortId = "Visiblity")
    {
        var appearanceBuilder =  new ConditionalAppearancePropertyBuilder<TProp, T>(builder, shortId);

        (builder as IBuilderManager).AddBuilder(appearanceBuilder);

        return appearanceBuilder;
    }

}

Don't focus on to much detail here, this just returns a new IBuilder for PropertyBuilder<TProp, T>.UsingAppearance

The implementation it self is very simple, but needs to handle the DefaultValues of the AppearanceAttribute, so it needs to use state, to init the _AppearanceItemTypeValue and the AppearanceContext correctly

public class ConditionalAppearancePropertyBuilder<TProp, T> : IBuilder
{
    private readonly PropertyBuilder<TProp, T> _Builder;

    private string _AppearanceItemTypeValue;

    private string _Context;

    internal AppearanceAttribute _Attribute;

    public ConditionalAppearancePropertyBuilder(PropertyBuilder<TProp, T> builder, string shortId)
    {
        _Builder = builder;
        _Attribute = new AppearanceAttribute(typeof(T).FullName + "." + builder.MemberInfo.Name + "." + shortId);
        builder.WithAttribute(_Attribute);
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> UsingForeColor(Color color)
    {
        var converter = System.ComponentModel.TypeDescriptor.GetConverter(color);
        _Attribute.FontColor = converter.ConvertToString(color);
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> UsingBackColor(Color color)
    {
        var converter = System.ComponentModel.TypeDescriptor.GetConverter(color);
        _Attribute.BackColor = converter.ConvertToString(color);
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> UsingFontStyle(FontStyle style)
    {
        _Attribute.FontStyle = style;
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> HavingPriority(int priority)
    {
        _Attribute.Priority = priority;
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> IsVisible()
    {
        _Attribute.Visibility = ViewItemVisibility.Show;
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> IsVisibleAsEmptySpace()
    {
        _Attribute.Visibility = ViewItemVisibility.ShowEmptySpace;
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> IsNotVisible()
    {
        _Attribute.Visibility = ViewItemVisibility.Hide;
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> IsEnabled()
    {
        _Attribute.Enabled = true;
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> IsNotEnabled()
    {
        _Attribute.Enabled = false;
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> When(string criteria)
    {
        _Attribute.Criteria = criteria;
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> When(CriteriaOperator criteria)
    {
        _Attribute.Criteria = criteria.ToString();
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> ForItemsOfType(AppearanceItemType appearanceItemType)
    {
        return ForItemsOfType(appearanceItemType.ToString());
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> ForItemsOfType(string appearanceItemType)
    {
        _AppearanceItemTypeValue = _AppearanceItemTypeValue.AppendString(appearanceItemType);
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> ForLayoutItems()
    {
        return ForItemsOfType(AppearanceItemType.LayoutItem);
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> ForViewItems()
    {
        return ForItemsOfType(AppearanceItemType.ViewItem);
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> ForActions()
    {
        return ForItemsOfType(AppearanceItemType.Action);
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> InTheContextOf(string context)
    {
        _Context = _Context.AppendString(context);
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> InDetailViewContext()
    {
        return InTheContextOf(ViewType.DetailView.ToString());
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> InAnyContext()
    {
        return InTheContextOf(ViewType.Any.ToString());
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> InListViewContext()
    {
        return InTheContextOf(ViewType.ListView.ToString());
    }

    public PropertyBuilder<TProp, T> Build()
    {
        return _Builder;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> Targeting(string property)
    {
        _Attribute.TargetItems = _Attribute.TargetItems.AppendString(property);
        return this;
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> TargetingAll()
    {
        return Targeting("*");
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> ExceptingTarget(string property)
    {
        return Targeting(property);
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> Targeting<TProp2>(Expression<Func<T, TProp2>> property)
    {
        return Targeting(_Builder._Fields.GetPropertyName(property));
    }

    public ConditionalAppearancePropertyBuilder<TProp, T> ExceptingTarget<TProp2>(Expression<Func<T, TProp2>> property)
    {
        return ExceptingTarget(_Builder._Fields.GetPropertyName(property));
    }

    void IBuilder.Build()
    {
        if (!string.IsNullOrEmpty(_AppearanceItemTypeValue))
            _Attribute.AppearanceItemType = _AppearanceItemTypeValue;

        if (!string.IsNullOrEmpty(_Context))
            _Attribute.Context = _Context;
    }
}

##Where do i get it?##

Currently it is easy as brush your teeth using NuGet:

  • For XAF-Only Attributes:

Install-Package Para.FluentModelBuilder.XAF

  • For the ConditionalAppearance part use:

Install-Package Para.FluentModelBuilder.ConditionalAppearance

##Questions?##

Currently this is very alpha stuff, but it works brilliant for this easy example so far :)

Feel free to contact, fork or ask me for questions on twitter, facebook or Email:

About

Fluent Model Builder for the DevExpress.ExpressApp Framework

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages