Composite UI Application Block


Estos días he estado revisando un programilla de ejemplo que empecé a principios de año ( aprovechando que me quede en paro😛 jeje ) y que ha estado parado desde entonces … si es que soy un vago juas

La aplicación iba a ser un port de una aplicacion vieja a .NET ( que ha quedado en nada en cuanto he vuelto a currar jajaja ).

Una de las cosas en las que tenia más dudas era en como implementar la UI … habia algo claro tendría que usar el patrón MVC ( model view controller ) o el MVP ( model view presenter ).

Como tras leer un poco del tema quedó claro que iba a ser un curro de chinos y no estaba el tema para perder el tiempo … anduve buscando por inet hastq ue di con el Composite UI Application Block (en adelante CAB a secas para abreviar), dando gracias que estoy desde entonces …

El CAB ofrece la infraestructura necesaria para el desarrollo de Smart Clients ( estos de Microsoft ya no saben que nombre ponerle a las cosas … )

En su momento no me dio tiempo a ver mucho pero … algunas de las cosas interesantes que tiene son:

· Un Shell. Es el punto de entrada principal de la aplicación la implementación del sehll se divide en varias partes:

  • Un formulario. En donde mostrar la UI de la aplicación ( menus, barras de herramientas, las vistas de la aplicación , etc … ) y al que se debe añadir un o varios WorkSpaces para mostrar las vistas de la aplicación ( Smart Parts ). El CAB viene con varias implementaciones de Workspaces, en el caso del ejemplo que sigue se utiliza una implementación especifica ( TabbedDocumentWorkspace ).

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Printing;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using Microsoft.Practices.CompositeUI;
using Microsoft.Practices.CompositeUI.Services;
using Microsoft.Practices.ObjectBuilder;
using Microsoft.Practices.CompositeUI.Commands;
using Microsoft.Practices.CompositeUI.EventBroker;

namespace Cab.Test.Shell
{
    public partial class ShellForm : System.Windows.Forms.Form
    {
        #region · Fields ·

        private WorkItem workItem;
        private IWorkItemTypeCatalogService workItemTypeCatalog;

        #endregion

        #region · Constructors ·

        public ShellForm()
        {
            InitializeComponent();
        }

        [InjectionConstructor]
        public ShellForm(WorkItem workItem, IWorkItemTypeCatalogService workItemTypeCatalog)
            : this()
        {
            this.workItem = workItem;
            this.workItemTypeCatalog = workItemTypeCatalog;

            // Inicializamos el workspace
            this.workItem.Workspaces.Add(new TabbedDocumentWorkspace(), "contentWorkspace");
        }

        #endregion
    }
}

En el constructor que toma parametros se utiliza un atributo que hará que se le pasen los parámetros utilizando dependency injection.

  • Un WorkItem. Para implementar el caso de uso del Sehll. Este será el RootWorkItem de la aplicación.

using System;
using Microsoft.Practices.CompositeUI;

namespace Cab.Test.Shell
{
    public class ShellWorkItem : WorkItem
    {
    }
}
  • Una implementación de FormShellApplication. Esta será la clase encargada de cargar la aplicación ( shell, modulos, etc … )

using System;
using System.Text;
using System.Windows.Forms;
using Microsoft.Practices.CompositeUI;
using Microsoft.Practices.CompositeUI.WinForms;

namespace Cab.Test.Shell
{
    public class ShellApplication : FormShellApplication<ShellWorkItem, ShellForm>
    {
        #region · Singleton Instance ·

        public static readonly ShellApplication Instance = new ShellApplication();

        #endregion

        #region · Constructors ·

        private ShellApplication()
            : base()
        {
        }

        #endregion

        #region · Protected Methods ·

        protected override void AfterShellCreated()
        {
            base.AfterShellCreated();

            // Registro de los menus barras de herramientas, etc ... (
            RootWorkItem.UIExtensionSites.RegisterSite(UIExtensionConstants.MainMenuStrip, Shell.MainMenuStrip);
            RootWorkItem.UIExtensionSites.RegisterSite(UIExtensionConstants.MainToolStrip, Shell.MainToolStrip);
        }

        protected override void AddServices()
        {
            base.AddServices();

            // Añadir los servicios que deban estar disponibles

            // RootWorkItem.Services.Add(typeof(...), xxx);
        }

        #endregion

        #region · Unhandled Exception ·

        public override void OnUnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            // Procesar la exceción
        }

        #endregion
    }
}

Por último hay que ejeuctar la aplicacón para lo que bastará hacer esto:

ShellApplication.Instance.Run();

· WorkItems. Que ( sino me equivoco ) sirven para implementar los casos de uso, utilizando MVC/MVP, en donde:

    • Modelo. Se representa en el estado del WorkItem.
    • Vista. Los WorkItems pueden tener asociadas una o mas vistas.
    • Controlador/Presentador. Cada vista tendrá asociado un controlador/presentador.

· Event Broker ( En mi opinion casi casi lo mejor de todo lo que he visto del CAB hasta ahora … sencillamente acojonante por las posibilidades que tiene )

Se pueden utilizar utilizando atributos o por código.

Un ejemplo utilizando atributos:

[EventPublication("event://ViewStateChanged", PublicationScope.WorkItem)]
public event EventHandler<ViewStateChangedEventArgs> ViewStateChanged;[EventSubscription("event://ViewStateChanged", Thread = ThreadOption.UserInterface)]
public void ViewStateChanged(object sender, ViewStateChangedEventArgs e)
{
    SmartPartControlsUpdater.UpdateSmartPartControls(this, e.NewState);
}

No es necesario hacer nada más, el propio sistema se encarga ( gracias al ObjectBuilder que es un framework de Dependency Injection ) de asociar el elemento que publica el evento ( un mismo evento puede ser publicado por más de un elemento ) con los suscriptores que se hayan configurado.

· Un Command Manager. Sino me equivoco es una implementación del patrón Command. Útil cuando un comando determinado se puede ejecutar desde variso sitios distintos ) por ejemplo una opción de menú y un botón deun abarra de herramientas.

Un manejador para un comando ( por ejemplo para la opción de menú que permite salir de la aplicación ) se definiría asi:

[CommandHandler("FileExit")]
public void OnFileExit(object sender, EventArgs e)
{
    // Procesar el comando
}

Responder

Por favor, inicia sesión con uno de estos métodos para publicar tu comentario:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s