Friday, February 22, 2013

Dashboards in the real world – A Scotland strike!

The DevExpress Universal Subscription now includes an interactive data visualization Dashboard for Windows, the Web and Mobile devices. DevExpress Dashboard helps you deliver solutions that allow any enterprise to visually explore business trends using stunning and easily understood performance indicators.

If you are an XAF user, you already know that a framework such as XAF provides reusable building blocks to quickly build feature-rich business applications for Windows or the Web. In this post, I’ll discuss how Stephen Manderson, an XAF user from Scotland merged the capabilities of XAF and DevExpress Dashboard to create a new reusable XAF Dashboard module.

To best demo this Dashboard integration, we’ll use our XVideoRental RWA demo. The sample is available for your review at the bottom of this post. 

XAF users already know that dashboard support is part of the shipping product.  A few days ago I posted Visiting Dashboards where I discussed possible use case scenarios and extensions of the native implementation in order to deliver dashboard solutions to address real problems without writing any code!

Stephen Manderson was recently asked by a customer if it was possible for end users to create dashboards without going through IT to request changes and modifications to their system. The solution as you can imagine was the migration of the Dashboard Suite to his XAF application.

Stephen’s goals were simple.

  1. Create dashboards like any other BO at runtime.
  2. Pass any number of Target Persistent Object as data sources.
  3. Restrict access to dashboards based on Roles.

The DashboardDesigner

 

This step is really easy, we only need to drag this DashboardDesigner component into a simple empty windows form:

 

image

 

Displaying custom forms in XAF requires no special skills and is well documented: How do I show a custom window?

 

Create dashboards like any other BO at runtime

Working with XAF is straight forward. We have a DX component (DashboardDesigner) and we want to integrate it. Almost all our components are serializable and the DashboardDesigner is no exception. This means that we need a Persistent object to host the Xml for the layout and a collection of XAF BO Types that will be assigned as data sources.

To start we can use the following interface:

public interface IDashboardDefinition {

    int Index { get; set; }

    string Name { get; set; }

    Image Icon { get; set; }

    bool Active { get; set; }

    string Xml { get; set; }

    IList<ITypeWrapper> DashboardTypes { get; }

}

For the sake of simplicity I wont post the full implementation however you can grab it and follow its history in eXpand’s github repo or in the sample at the end of this post.

 

The Xml property along with the Designer’s LoadFromXml method can be used to load the Designer’s layout. So we need:

  1. To create a SimpleAction in a ViewController. We choose a ViewController instead of any other Controller simply because targeting a certain view and not the whole app.
  2. Then we configure the controller a bit further, to activate it only for BO that implements IDashboardDefinition.
  3. Finally we subscribe to SimpleAction’s Execute event, and we load the Windows form with the Dashboard designer component.

public class DashboardDesignerController : ViewController {

    readonly SimpleAction _dashboardEdit;

 

    public DashboardDesignerController() {

        _dashboardEdit = new SimpleAction(this, "DashboardEdit", PredefinedCategory.Edit);

        TargetObjectType = typeof(IDashboardDefinition);

        _dashboardEdit.Execute += dashboardEdit_Execute;

    }

 

    public SimpleAction DashboardEditAction {

        get { return _dashboardEdit; }

    }

 

    void dashboardEdit_Execute(object sender, SimpleActionExecuteEventArgs e) {

        using (var form = new DashboardDesignerForm()) {

            new XPObjectSpaceAwareControlInitializer(form, Application);

            form.LoadTemplate(View.CurrentObject as IDashboardDefinition);

            form.ShowDialog();

        }

    }

 

In the above snippet we chose to implement the LoadTemplate method in the DashboardDesignerForm because the Dashboard’s XML loading is not of XAF concern. This form is simply another separate windows based layer.

Visualizing our business data in the designer

The dashboard designer allows for us to see our XAF data and shape our dashboards in real time as shown:

 

image

 

This designer is similar to our Reports designer but does not offer support for dynamic members aliases. However we covered them in depth in Dynamic member aliases from Application Model.

 

Dashboards in action

 

To visualize our dashboards we have to:

  1. Dynamically populate the navigation menu items

    We want to extend XAF’s functionality therefore we need to find the responsible built-in controller. This leads to ShowNavigationItemController where we can subscribe to its events and populate the navigation items from DashboardDefinition persistent objects. A possible implementation can be found in sample in WinDashboardNavigationController.cs or you can follow its history online.

  2. Modify XAF’s security system to restrict access to dashboards based on Roles.

    Since we really care about making it easy for the business user, the sample is using a possible implementation as discussed in depth in User friendly way to add permissions.

  3. Display the dashboard’s using built-in DashboardViewer control.

    Here we easily can follow an SDK sample: How to show custom forms and controls in XAF (Example). In short we need to create and return a new DashboardViewer control by overriding the CreateControlCore method of a PropertyEditor. In case we want to access extra system info we may use a different class than a PropertyEditor as discussed in Implement Custom Property Editors

Our active dashboards are linked in the “Dashboards” navigation group; this can be renamed and reordered so all changes are reflected within this group. The end result in post’s sample looks like:

 

image

 

image

 

image

What’s next?

Stephen is already working in a State Machine designer plus an integration with XAF’s KPI module which gives dashboard its full power according to his words! Forgot to mention that a web version of Dashboards is coming soon!

Big thanks to Stephen Manderson for sharing this cool XAF implementation with us, I am sure this post/contribution will boost his spirit/cv/carrier a bit Winking smile , We welcome any of you that wants to share it’s cool XAF stuff with the rest of us. Feel free to use our Support Center for this or our community project.

Please do  not forget your feedback about what we discussed today.

Unit next time Happy XAF’ing as always!

Download XVideoRental sample here. The sample contains the following modification

  1. User friendly way to add permission migrated in Common.Win.General namespace.
  2. XVideorental references DynamicMemberAliases.Module from Domain Components+ Calculated properties + Application Model.
  3. XVideorental references ProvidedAssociation.Module from Modifying Business Objects using Attributes.
  4. XVideorental references eXpand’s/Stephen's Dashboard module.

Subscribe to XAF feed
Subscribe to community feed

DiggIt!

Tuesday, February 5, 2013

Domain Components+ Calculated properties + Application Model

There is no official support for this scenario, however this does not mean that XAF is not designed with the highest standards. It means that we do not have docs and tests that can cover all possible combinations. However XAF is a flexible beast and we will go for supporting this case as short as possible.

Domain Components

With XAF it is possible to design business objects from interfaces! Given those interface DC with smart algorithms create concrete persistent class at runtime. It is possible to explore the DC dynamic assembly by overriding the in solution’s WinApplication descendant as shown:

public partial class DynamicMemberAliases2WindowsFormsApplication : WinApplication {

    protected override string GetDcAssemblyFilePath() {

        return Path.Combine(AppDomain.CurrentDomain.SetupInformation.ApplicationBase, DcAssemblyFileName);

    }

Exploring the DC assembly for the following DomainComponent1

[DomainComponent]

public interface DomainComponent1 {

    string Email { get; set; }

    string Twitter { get; set; }

}

public override void Setup(XafApplication application) {

    base.Setup(application);

    XafTypesInfo.Instance.RegisterEntity("Manager", typeof(DomainComponent1));

 

We find out that XAF creates on the fly the next Manager class which is a simple XPO persistent object and is specific to our DomainComponent1 (see RegisterEntity method above).

 

 

image

This is really great! We already know how to Dynamic member aliases from Application Model and we can apply the same technic to the Manager class which very conveniently is related only with DomainComponent1. However there is a small problem, although the Dynamic member aliases from Application Model will successfully create the members in the Manager class, XAF does not know their existence. In next section we will discuss how to workaround this.

The TypesInfo system

  1. XAF works with object types, so the XAF team introduced the TypesInfo, a wrapper around .NET Reflection. For UI creation and for all metadata operations XAF uses the TypesInfo system. In addition the TypesInfo system allows metadata modification with code as easy as it can be! The power is there my friends, because the UI is automatically generated by querying types and members from TypesInfo.
  2. XAF supports by default XPO and Entity Framework but is possible to support a custom ORM as well. To make this possible XAF team architecture a separate interface the ITypeInfoSource, which holds all Type metadata (e.g. for XPO-> XpoTypeInfoSource).

UI + business logic <— TypesInfo –> XpoTypeInfoSource OR EFTypeInfoSource OR any ITypeInfoSource.

In short the above theory leads to the conclusion that the XpoTypeInfoSource will be asked from XAF to provide the Type members for any class. Therefore, we only need to override the EnumsMembers method of XpoTypeInfoSource to provide our own implementation! Bellow you see a part of this implementation, you can find the rest in the sample at the end of the post.

public class XpandXpoTypeInfoSource : DevExpress.ExpressApp.DC.Xpo.XpoTypeInfoSource, ITypeInfoSource {

    void ITypeInfoSource.EnumMembers(TypeInfo info, EnumMembersHandler handler) {

        EnumMembers(info, handler);

        Type type = info.Type;

        if (TypeIsKnown(type)) {

            if (type.IsInterface) {

                EnumDCInterfaceMembers(info, handler);

            }

        }

    }

Wasn’t this amazingly fast and simple? I always emphasize that XAF has 2 advantages

  1. It is well architectured –> overridable.
  2. It is well architectured –> reusable.

Based on the above 2 assumptions you can download and use the DynamicMemberAliasesForDC.zip Winking smile.

We are happy to read your feedback about this!. Remember that your questions are the best candidates for future posts.

P.S. : eXpandFramework users only need to register the Core modules (see How to use an eXpand module with an existing XAF application)

Until next time, happy XAF’ing!

Subscribe to XAF feed
Subscribe to community feed

DiggIt!