[Curso] WPF para programadores de Windows Forms 7

Hola a todos de nuevo, volvemos a la carga con otro artículo sobre WFP para programadores de Windows Forms. En este articulo voy a hablar sobre los diferentes tipos de controles que hay en WPF y como encontramos similitud con los controles de WF.

En artículos anteriores estuvimos hablando sobre el árbol de herencia de WPF y sobre las diferentes clases de las que heredaba un control normal de WPF, pusimos como ejemplo Label, al ser un control que vamos a usar mucho en nuestras aplicaciones.

System.Object
  System.Windows.Threading.DispatcherObject
    System.Windows.DependencyObject
      System.Windows.Media.Visual
        System.Windows.UIElement
          System.Windows.FrameworkElement
            System.Windows.Controls.Control
              System.Windows.Controls.ContentControl
                System.Windows.Controls.Label

Ahora en este curso nos vamos a posicionar en System.Windows.UIElement y vamos a ver las diferentes ramas de las cuales salen los demás controles de WPF y ver que funcionalidad nos proporciona.

UIElement es la primera clase de WPF que tiene soporte para dibujado (heredado de Visual), soporte para entrada (Input, heredado de DispatcherObject) y soporte para RouteEvents. Así que técnicamente esta es la clase que tendríamos que usar si queremos empezar a dibujar algo en la pantalla, es la clase que da un soporte más primitivo para el dibujado. En la clase UIElement tenemos un método virtual OnRender que podemos sobreescribir en nuestras clase para poder implementar la funcionalidad personalizada de dibujado de esa clase, en la que se nos pasa un DrawingContext con el que dibujamos la UI del control. DrawingContextes muy parecido a la clase Graphics de GDI y de hecho tiene métodos muy parecidos.

Aquí podemos ver un ejemplo de un control que se dibuja a si mismo con este método.

public class WigoVisual : UIElement
    {
        private Pen pincel;
        public WigoVisual()
        {
            pincel = new Pen(new SolidColorBrush(Colors.Red), 20);
        }
        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);
            drawingContext.DrawLine(pincel, new Point(0, 0), new Point(100, 100));
            drawingContext.DrawRectangle(new SolidColorBrush(Colors.Green), new Pen(new SolidColorBrush(Colors.Blue), 5),
                new Rect(0, 0, 20, 20));
        }
    }

El control dibuja una línea desde (0,0) hasta (100,100) con el bolígrafo especificado, evidentemente esta clase no tiene soporte para Layout de ninguna manera porque nosotros al dibujar el control no tenemos en cuenta propiedades con Width o ActualWidth para dibujar la línea.

Como podréis comprender esta clase es muy básica en cuanto al soporte de Layout pero muy ponente para un dibujado más personalizado, si queremos ganar en funcionalidad existente tenemos que bajar en el árbol de herencia. La única clase pública del framework que hereda de UIElement es FrameworkElement, y es en esta clase donde se define mucha de la funcionalidad común de todos los controles del Framework, (es por eso que creo que se llama FrameworkElement).

FrameworkElement añade una serie de funcionalidad para que el soporte de Layout de la clase sea mucho más rico que con UIElement. Veámosla.

· Definición del sistema de Layout: define una serie de métodos que eran virtuales en UIElement para implementar el sistema de Layout de WPF.

· Define el árbol lógico de una aplicación WPF y deja la responsabilidad de definir cuál es a las clases herederas.

· Define los eventos del ciclo de vida de un control, eventos como Initialized, Loaded, Unloaded.

· Soporte para enlace a datos dinámico y búsqueda dinámica de recursos estáticos dentro del control.

· Define los estilos (Style) para los controles.

· Define el soporte para las animaciones de los controles.

FrameworkElement define una serie de propiedades básicas con las que podremos empezar a definir el Layout y los demás propiedades de la UI, a partir de esta clase podemos empezar a realizar Layout más complicados sin tener que explícitamente programarlos.

WPF permite que los programadores puedan sacar todo el partido del Layout a partir de una serie de clases que añaden funcionalidad especifica del nivel en el que se encuentran. Si volvemos atrás en el tiempo y recordamos como en Visual Basic 6 se hacían las cosas, los programadores más avanzados se hacían los cálculos ellos mismos para hacer que el control se moviese o fluyera a través del formulario, pero todos los cálculos tenían que ser hechos a mano, después con Windows Forms Microsoft nos dio dos propiedades muy interesantes de la clase Control Anchor y Dock, que permiten que un control se puedan quedar pillado a alguna de sus caras, o lo que es lo mismo que mantenga siempre la misma distancia. Todo este trabajo que antes se hacía a mano en Visual Basic ahora lo tenemos de “serie” dentro de Windows Forms, pues si seguimos avanzando en WPF ese cálculo de distancias se ha llevado al extremo, eso no significa que no se calcule internamente sino que no somos nosotros los responsables de hacer esos cálculos sino que WPF los hace por sí mismo.

Saludos. Luis.

[Evento] Taller de Nuevos interfaces para aplicaciones ( WPF/SILVERLIGHT)

El lunes de la semana que viene en Pamplona, se va a celebrar un evento para programadores sobre WPF / Silverlight.

Introducción al WPF / Silverlight

La mayoría de desarrollos actuales son como los de hace 15 o 20 años: La información se presenta de la misma manera, no se tiene en cuenta para nada la usabilidad de la UI y la experiencia de usuario (UX). Con Windows Presentation Foundation se pueden crear aplicaciones para Windows y la Web de una manera mucho más flexible, los controles son mucho más potentes que los Common Controls de Win32. Ahora podemos integrar multimedia, animaciones, 3D, databinding avanzado, efectos (PixelShaders), etc. Todos los controles de WPF están acelerados por el hardware de tarjeta gráfica gracias a Microsoft DirectX, así que ahora vamos a sacar potencia de la tarjeta gráfica para la composición de la UI de nuestras aplicaciones. WPF supone una revolución en la manera de hacer aplicaciones, además con XAML podemos integrar dentro del flujo de creación a los diseñadores. Ahora tanto programadores como diseñadores comparten XAML a través de Microsoft Blend y Visual Studio 2008.

Con este curso, se pretende exponer de manera general todas las características que hace de WPF una de las tecnologías más rompedoras de Microsoft para UX.

El Centro de Excelencia Microsoft .NET (CES) quiere poner en marcha una  intensa jornada sobre WPF / Silverlight en la que contaremos con uno de los mayores expertos  en la materia: Luis Guerrero.

  • Audiencia: Desarrolladores, Jefe de Proyecto,
  • Requisitos previos: Conocimientos del entorno Visual Studio 2005 / Visual Studio 2008, UI

Temario:

· Introducción a WPF ¿Por qué otra herramienta para componer aplicaciones? Historia

· XAML, herramientas para WPF / Silverlight

· Layout

· Controles

· Dependency properties

· Routed Input Events

· Animaciones

· Databinding

· Estilos (Style)

 

 

http://www.cesnavarra.net/Lists/Eventos%20CES/DispForm1.aspx?List=05834153%2Deec1%2D4089%2Da40e%2D5355dbd305f4&ID=90&Source=http%3A%2F%2Fwww%2Ecesnavarra%2Enet%2Fdefault%2Easpx

WPF Advanced – ISealable

Recientemente en un cliente me ha ocurrido un caso muy extraño con las Dependecy Property de WPF y quiero escribir sobre el tema. Es un poco enrevesado pero creo que puede ser útil. Veamos.

WPF tiene un sistema de Binding muy potente que hace que se puedan hacer enlaces a datos a entidades de negocio. Pues bien el caso es que para que una clase pueda tener Dependency Property (DP a partir de ahora), es necesario que heredemos como mínimo de la clase DependencyObject que permite que una clase almacene DP, pues bien el caso es que mis entidades de negocio heredan de esta clase para que las propiedades que lo define sean DP y poder utilizar toda la potencia de WPF, hasta aquí todo bien. Para lo que no estéis tan al tanto de DP es un sistema que permite tener propiedades con metadatos y un sistema centralizado de almacenamiento de valores. Para definir un DP es así.

public static readonly DependencyProperty CurrentBusinessEntityProperty =
    DependencyProperty.Register("CurrentBusinessEntity", typeof(BusinesEntity), typeof(BusinessManager), new UIPropertyMetadata(new BusinesEntity()));

public BusinesEntity CurrentBusinessEntity
{
    get { return (BusinesEntity)GetValue(CurrentBusinessEntityProperty); }
    set { SetValue(CurrentBusinessEntityProperty, value); }
}

Si os fijáis en el primer parámetro del UIPropertyMetadata es el valor predeterminado del DP, hay que tener en cuenta que esto se inicializa en el constructor de tipo (static en C#) y que por tanto es seguro frente a subprocesos. Pues bien si el valor predeterminado que nosotros usamos es un objeto que hereda de DependencyObject WPF lanza una excepción. La excepción es:

clip_image002

Default value for the ‘CurrentBusinessEntity’ property cannot be bound to a specific thread.

Es algo bastante raro, porque si pongo null funciona si hago otro tipo de DP funciona correctamente y solamente si utilizo como valor predeterminado una entidad de negocio mía (que hereda de DependencyObject) la no cosa funciona. Pero la excepción que se nos lanza no nos da mucha información. Utilizando el código fuente del framework y depurando todo el proceso de inicialización del DP, llego hasta este bonito trozo del código.

if (checkThreadAffinity) 
{
// If the default value is a DispatcherObject with thread affinity 
// we cannot accept it as a default value. If it implements ISealable
// we attempt to seal it; if not we throw  an exception. Types not
// deriving from DispatcherObject are allowed - it is up to the user to
// make any custom types free-threaded. 

DispatcherObject dispatcherObject = defaultValue as DispatcherObject; 

if (dispatcherObject != null && dispatcherObject.Dispatcher != null)
{ 
    // Try to make the DispatcherObject free-threaded if it's an
    // ISealable.

    ISealable valueAsISealable = dispatcherObject as ISealable; 

    if (valueAsISealable != null && valueAsISealable.CanSeal) 
    { 
        Invariant.Assert (!valueAsISealable.IsSealed,
               "A Sealed ISealable must not have dispatcher affinity"); 

        valueAsISealable.Seal();

        Invariant.Assert(dispatcherObject.Dispatcher == null, 
            "ISealable.Seal() failed after ISealable.CanSeal returned true");
    } 
    else 
    {
        throw new ArgumentException(SR.Get(SRID.DefaultValueMustBeFreeThreaded, propertyName)); 
    }
}
}

En el que básicamente los señores que prograron WPF vienen a decir algo así como que el valor predeterminado es un DispathcerObject (en mi caso lo es) no pueden acceptar solo si implementa ISealable entonces lo sellan y si no pueden lanzan una excepción.

Una bonita manera de encontrar el error, continuando la investiagación, me dispongo pues a que mio clase implemente esta interfaz ISealable, pero cual es mi sorpresa que la interfaz no existe. La busco en el MSDN nada, abro el reflecto y para mi sorpresa me encuentro con esto

[FriendAccessAllowed]

internal interface ISealable

{

// Methods

void Seal();

// Properties

bool CanSeal { get; }

bool IsSealed { get; }

}

Que la internfaz es internal y encima se permite el acceso de los ensamblado amigos, pues con el mismo reflecto abierto me dispongo pues a ver que clases dentro del framework (por curiosidad mas que nada) implementan esta fatídica interfaz, y me encuentro con esto:

clip_image004

Que las tres únicas clases que implementan esa funcionalidad son FrameworkTemplate, Freezable y Style.

Los que halláis leído otras entradas de WPF sabréis que Freezable está presente en el árbol de algunos tipos de controles de WPF permitiendo que el contenido del control se pueda de alguna manera congelar para aumentar el rendimiento de la aplicación. Pues bien parece que para que pueda poner como valor predeterminado una entidad mia de negocio tengo que heredar no de DependencyObject sino de Freezable.

Resumen:

Esta una bonita historia sobre como WPF es a veces un sistema muy complejo que creo que ni la gente de Microsoft a veces entiende, no porque esté mal diseñada, sino por lo compleja que es. Así que me pareció un exceso tener que heredar de Freezable únicamente por poder poner una entidad de negocio mía como valor predeterminado de un DP, así que lo deje como estaba antes.

Ahora bien porque WPF hace esto?, al ser la DP usadas por una clase que hereda de DependencyObject esta clase tiene una propiedad muy importante el Dispatcher que es el gestor de threads dentro de WPF así que supongo que la comprobación vendrá por si el objeto se está iniciando en un thread que no contiene un Dispatcher o se tendrá que hacer invocación. Y por *intentar* hacer la vida más sencilla a los programadores Microsoft ofrece la clase Freezable, pero por lo menos lanza una excepción explicando el tema o algo porque sino la gente se vuelve loca.

 

Aquí teneis el codigo fuente de ejemplo [SealedExample.rar]

Saludos. Luis.

CCR and DSS Toolkit 2008

Microsoft ha anunciado a través del blog de Robotics Studio la disponibilidad de CCR and DSS Toolkit 2008.

¿Qué es CCR and DSS Toolkit 2008?, como he hablado anteriormente Robotics Studio tiene dos componentes principales CCR (Concurrency and coordinator runtime) y DSS (Descentralizated Software Services), que hacen posible que todo el procesamiento de los mensajes que los Robots y el software procesan sean concurrentes, seguros frente a subprocesos y además los servicios que se diseñen sean bajamente acoplados y descentralizados de serie.

También explique en mi blog que estos dos componentes, que están aislados dentro de Robotics Studio, se podían usar para el desarrollo normal de aplicaciones distribuidas y concurrentes, tanto aplicaciones de escritorio / servidor como también en Compact Framework, así que aquí tenéis la prueba de cómo Microsoft se ha dado cuenta de lo mismo y ahora lo vente en un cómodo paquete para empresas J, en la web http://www.microsoft.com/ccrdss/ podéis encontrar información sobre licencias, precios y demás.