Búsqueda Ingecaam

Búsqueda personalizada

Resultados Búsqueda

lunes 19 de diciembre de 2011

Entendiendo las propiedades de dependencia en Silverligth

He decidido escribir este post, como ayuda para la cápsula de Silverligt relacionada con la implementación de Content Controls, en donde se requiere definir para el Content Control una propiedad de este tipo.

Haber, las propiedades de dependencia, aunque sin de pronto saberlo, las has usado cada vez que le asignas su valor a una propiedad de las principales de los controles que hemos visto: TextBox, CheckBox, Button o TextBlock. Ello porque las propiedades principales de los controles que mayormente usamos, todas permiten en un momento determinado la aplicación de: Animaciones, Estilos o Enlace a datos, como se verá en otras cápsulas.

Las propiedades de dependencia son entonces propiedades que permiten extender la funcionalidad de la propia propiedad. Es decir, tomemos como ejemplo, la propiedad Text del control TextBlock. Con esta propiedad, podemos definir el texto que muestra el TextBlock, allí usamos la funcionalidad normal de la propiedad Text. Sin embargo, como veremos en cápsulas sucesivas, se puede utilizar la propiedad Text, para mostrar la información proveniente de una fuente de datos, es decir, podemos enlazar la propiedad a una fuente de datos con una sintaxis dada:

<TextBlock Text="{Binding Team.TeamName}"/>

En este caso, la propiedad Text se enlaza a una fuente de datos, para tomar el nombre de un equipo.

Por ello, la propiedad Text es una propiedad de dependencia, porque, en un momento dado, permite extender su funcionalidad básica que es definir el texto para el TextBlock y, en este caso particular, enlazarse previamente a una fuente de datos para tomar la información.

Los objetos o controles de Silverligt son objetos DependencyObject y deben serlo porque la mayoría de ellos permiten la animación, enlazado a datos o la aplicación de estilos de al menos una propiedad y para permitir dichas acciones sobre la propiedad éstas deben ser propiedades de dependencia que solo se pueden definir en objetos de dependencia.

Para que un objeto permita en una propiedad de dependencia, el enlazado a datos, debe también heredar de FrameworkElement.

En el caso del TextBlock, podemos enlazar la propiedad Text a una fuente de datos y como muestra la imagen, vemos, en su jerarquía de clase, que hereda de FrameworkElement:

JerarquiaHerenciaTextBlock

También, vemos como es un DependencyObject.

En Silverligth, nosotros podemos definir nuestras propias propiedades de dependencia para proporcionarles a los Content Controles, User Controls o demás tipos de controles que implementemos, propiedades que permitan el enlazado de datos, el establecimiento de animaciones o la aplicación de estilos cuando sea requerido.

Las propiedades de dependencia se definen, en código, de manera similar a las propiedades convencionales clásicas que se respaldaban en un campo privado. A continuación, el comparativo:

Propiedad clásica convencional

Propiedad de dependencia

private bool isSpinning;

 

 

 

 

 

public bool IsSpinning

{

get { return isSpinning;}

set { isSpinning = value;}

}

public static readonly DependencyProperty IsSpinningProperty =

DependencyProperty.Register(

"IsSpinning", typeof(Boolean),

typeof(SilverlightExampleClass), null

);

 

public bool IsSpinning

{

get { return (bool)GetValue(IsSpinningProperty); }

set { SetValue(IsSpinningProperty, value); }

}

Es decir, en lugar del campo privado se usa el tipo DependencyProperty estático público y de solo lectura, que por convención lleva el nombre de la propiedad de dependencia seguido del término Property (<NombrePropiedad>Property. Ejemplo:IsSpinningProperty);  y para obtener y asignar el valor de la propiedad se deben usar los métodos GetValue y SetValue.

También notar como la propiedad de dependencia se debe registrar utilizando el método DependencyProperty.Register.

Que recibe como parámetros:

  • El nombre de la propiedad de dependencia a registrar
  • Su tipo
  • El tipo de la clase donde se registra la propiedad de dependencia
  • Y, por último, de manera opcional, información de metadata de la propiedad de dependencia.

En resumen, entonces, tenemos que las propiedades de dependencia permiten extender la funcionalidad de la propiedad para permitir: Animaciones, enlace a datos o aplicación de estilos. Sin embargo, las propiedades de dependencia presentan otra característica importante y es la de proporcionar devoluciones de llamada que puedan propagar sus cambios a otras propiedades. Es decir, las devoluciones de llamada se pueden utilizar para notificar o cambiar los valores de las propiedades relacionadas, de un modo sincrónico en general.

Para usar las devoluciones de llamada, las definimos en la información de metadata del método de registro. Por ejemplo:

public static readonly DependencyProperty HeaderContentProperty =
    DependencyProperty.Register("HeaderContent", typeof(object), typeof(MiContentControl),
    new PropertyMetadata(new TextBlock() { Text="Usar un TextBlock"}, new PropertyChangedCallback(OnHeaderContentChanged)));
 
static void OnHeaderContentChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    MiContentControl miContentControl = (MiContentControl)sender;
 
    if (!(e.NewValue is TextBlock))
    {
        miContentControl.ClearValue(HeaderContentProperty);
    }
}
 
public object HeaderContent { 
    get { return (object)GetValue(HeaderContentProperty); } 
    set { SetValue(HeaderContentProperty, value); } 
}


Notar como, en este caso, definimos valor para la información de Metadata, en el método de registro:


new PropertyMetadata(new TextBlock() { Text="Usar un TextBlock"}, new PropertyChangedCallback(OnHeaderContentChanged))


El objeto PropertyMetadata recibe dos parámetros:



  • El valor por defecto de la propiedad. Que para el caso es:

        new TextBlock() { Text="Usar un TextBlock"}



  • La definición de la devolución de la llamada. Y corresponde a:

         new PropertyChangedCallback(OnHeaderContentChanged)


Es en la implementación de la devolución de llamada donde se puede hacer la modificación de las propiedades relacionadas con base al valor de la propiedad de dependencia. En el ejemplo, la implementación de la devolución de la llamada corresponde a:




static void OnHeaderContentChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
    MiContentControl miContentControl = (MiContentControl)sender;
 
    if (!(e.NewValue is TextBlock))
    {        
 
       //Se asigna de nuevo como valor de la propiedad el definido por defecto
        miContentControl.ClearValue(HeaderContentProperty);
    }
}


El ejemplo corresponde a la implementación de una propiedad de dependencia para definir el encabezado que tendrá un Content Control. Por defecto (resaltado de azul), se define que su valor será un TextBlock con el texto: Usar un TextBlock y en la implementación de la devolución de llamada, se controla que si el valor de la propiedad, luego de modificado por el usuario (NewValue), no es un TextBlock; se le asigna su valor por defecto. Esto se logra al llamar el método ClearValue pasándole como parámetro la propiedad de dependencia. De esta forma, se usa la devolución de llamada, para controlar que solo se pueda usar un TextBlock como encabezado.

El código precedente, entonces, también ilustra otras características que poseen las propiedades de dependencia que son: la posibilidad de definirles un valor por defecto y la posibilidad de restablecer ese valor por defecto, en cualquier momento, por medio del método ClearValue que recibe como parámetro la propiedad de dependencia.

Finalmente, como también es ilustrado, en la implementación de la devolución de la llamada podemos acceder a la información de los distintos valores de la propiedad de dependencia para la toma de decisiones:

NewValue: Valor después de realizado el cambio del valor de la propiedad de dependencia.

OldValue: Valor de la propiedad antes de realizado el cambio.

Resumen, en mapa conceptual:

ResumenPropiedadDependencia

martes 13 de diciembre de 2011

Base de conocimiento

Categoría
Descripción
Observación
Silverligth La propiedad FontStretch del TextBlock y TextBox se encuentra definida solo por compatibilidad con WPF. En Silverligth esta propiedad no tiene efecto, ni siquiera para fuentes OpenType como era en el caso de WPF. http://forums.silverlight.net/
p/126686/284601.aspx

Silverligth En lo que respecta a la programación asíncrona, en Silverligth, no es soportada la forma de llamar al método BeginInvoke desde un delegado.

Delegate.BeginInvoke

 

martes 6 de diciembre de 2011

Mi segunda cápsula en Avanet

Estudio del control WrapPanel

lunes 5 de diciembre de 2011

Mi primera cápsula de Silverlight en Avanet

 

Me pareció sumamente enriquecedor realizar un video de enseñanza en cuanto al manejo de la tecnología SilverLigth, para mi nueva comunidad Avanet.

He aquí el video:

Explicación del uso del control DockPanel en SilverLigth

Si tienen comentarios, sugerencias o preguntas. Favor, realizarlas, estaré atento para colaborarles en lo que pueda.

viernes 25 de marzo de 2011

Herramienta para generación de Scripts de inserción de datos de forma ágil en SQL Server

 

Una tarea que puede tomar, algunas veces mucho tiempo y que puede ser desgastante, es generar scripts de inserción de datos, en tablas. Y lo frustrante, es que, en muchos escenarios, la información ya se tiene en las propias tablas, pero para facilitar el cargado inicial de datos, en otras bases de datos o el transporte de la misma información, se requiere disponer del Script de inserción de datos.
 
En este escenario, aplica muy bien, la herramienta o procedimiento almacenado InsertGenerator que se puede obtener en este enlace:
http://www.codeproject.com/KB/database/InsertGeneratorPack.aspx
 
Lo que se hace es crear el procedimiento almacenado, en la base de datos, donde se encuentran las tablas con la información, que se desea tener en el Script de inserción y ejecutarlo pasándole, como parámetro, la tabla, para la que se desea generar el Script, así:
 
exec InsertGenerator ClasificacionesVehiculo
 
Con sólo eso, ya, en la ventana de resultados de ejecución de las consultas, de la herramienta de ejecución de consultas de SQL Server, aparece, el Script de Insert.

blog1

Nada más fácil. ¡Que vacano!.
 
Sin embargo, como lo que se quería era sacar la información o script de inserción de varias tablas, se investigó un poco más y, primero que todo, se creó un Script, para generar las instrucciones de insert sobre las tablas requeridas:
 
exec BDHERMESPROD20110310.dbo.InsertGenerator ClasificacionesVehiculo
exec BDHERMESPROD20110310.dbo.InsertGenerator FormasPago
exec BDHERMESPROD20110310.dbo.InsertGenerator GruposUsuario
exec BDHERMESPROD20110310.dbo.InsertGenerator Menus
exec BDHERMESPROD20110310.dbo.InsertGenerator Formularios
exec BDHERMESPROD20110310.dbo.InsertGenerator Plataformas
 

 
Fijarse como, se indica la base de datos donde se encuentra definido el procedimiento almacenado InsertGenerator y el propósito de ello es ejecutar el Script desde la consola del DOS, a través de la utilidad SQLCMD y poder generar, así, de una vez, el script de inserción, para cada tabla, de una forma aún más rápida:
 
sqlcmd -SMVMsb102 -UIUSR_HERMES -PIUSR_HERMES -i GeneScriptsTiposBasicos.sql -o insert.sql
 
Aquí, entonces,
 
S: El servidor es MVMsb102
U: EL usuario IUSR_HERMES
P: La clave, la misma
i: El Script a ejecutar, en este caso, GeneScriptsTiposBasicos.sql, que contiene las instrucciones de generación del insert sobre las tablas, mostradas arriba.
o: El archivo donde quedará el resultado de la ejecución del Script GeneScriptsTiposBasicos.sql
 
Al dar enter y ejecutar el comando, efectivamente, se genera el Script, con las instrucciones de inserción sobre las tablas. Así:


blog2 

Lo que resta  entonces es utilizar la instrucción USE, para indicar la base de datos donde se ejecutarán los Scripts de inserción y modificar los textos del tipo:
(x filas afectadas)
Por la palabra reservada GO, como se muestra a continuación y listo.

blog3

De esta forma,  se obtienen los Scripts de inserción de datos sobre varias tablas, de una forma ágil y rápida.


Resumen de pasos:
1.       Crear el procedimiento InsertGenerator en la BD donde se encuentran las tablas con la información.
2.       Crear el Script de generación de inserts sobre tablas
Ejemplo:
exec BDHERMESPROD20110310.dbo.InsertGenerator ClasificacionesVehiculo
exec BDHERMESPROD20110310.dbo.InsertGenerator FormasPago
3.       Ejecutar la instrucción:
sqlcmd -S -U -P -i –o
 
En la consola de DOS.
Especificando, apropiadamente:
El servidor, el usuario y clave de conexión a la BD, el Script a ejecutar y el nombre del archivo con el resultado
4.       Adecuar el Script, para su ejecución, en SQL Server. Es decir, indicar la base de datos con USE y colocar los GO.

Espero que esta herramienta sea de utilidad.

miércoles 23 de marzo de 2011

Covarianza y contravarianza en C#

 

Esto son otros nuevos conceptos que vienen con el Framewrok 4.0 de C# y son duros de entender. Mi propósito en este articulo, como el de muchos autores, es dar a entender los conceptos que hay detrás de la covarianza y contravarianza, para que así estos conceptos se puedan aplicar de una manera más natural, en los desarrollos de Software que así lo requieran.
 
Empecemos por indicar que, desde el punto de la física,
 
Co y Contra: Implican dualidad, lo que significa que los términos van juntos.
Varianza: implica movimiento.
 
Se puede inferir, entonces, que en estos términos, Covarianza significa “Con el movimiento” y Contravarianza “Contra el movimiento o en sentido opuesto al movimiento”.
 
Ahora, en nuestro campo, la programación orientada a objetos, en el marco del concepto de herencia, identificamos dos tipos de objetos:
 
1.       Tipos base
2.       Tipos derivados
 
Así las cosas, podemos imaginarnos a un tipo base interactuando en un programa (es decir, tener un movimiento o acción o cambio)  y sustituir el tipo base por el tipo derivado, ya que el tipo derivado “es un” tipo base. Por tanto, cuando es equivalente tener a un tipo derivado en lugar del tipo base, estamos ante la covarianza. La acción o movimiento que afecte al tipo base, le afecta en igual medida al tipo derivado y, por ello, son covariantes.
 
En sentido opuesto, se define la contravarianza, en donde es el tipo derivado el que se puede sustituir por el tipo base.
 
En la siguiente imagen, se trata de ilustrar ambos conceptos:

 CoContraVarianza
 
Con el auge y manipulación de delegados, se pensó en incorporar, en el lenguaje, características que permitieran realizar manipulaciones de estos, esperadas, dada una relación de herencia entre tipos dados.
 
Ejemplo:
 
Gato hereda de Animal y, entonces, se puede tener el siguiente delegado genérico:
 
delegate T Func1<T>();
 
Siendo así las cosas, podemos tener una instancia de este delegado que retorne un gato:
 
 
public Cat MyFunc()
{
    return new Cat();
   }
 
    Func1<Cat> cat = MyFunc;
 
 
Debido a que un Gato es un Animal, tenderíamos a pensar, que debería ser viable asignar un Gato a un delegado que retorna un Animal, es decir, tener algo así:
 
Func1<Animal> animal = cat;
 
Sin embargo, hasta antes del Framework 4.0, una instrucción como esta sacaría error. A partir del Framework 4.0, es posible realizar la asignación, haciendo un cambio mínimo en la declaración del delegado. En particular, se requiere usar la palabra clave out, así:
 
delegate T Func1<out T>();
 
De esta forma, se puede lograr la asignación que hasta antes del Framework 4.0 no era posible y que se conoce como covarianza.
 
Ejemplo:
 
class Animal { }   

class Cat: Animal { }  

class Program    {    

delegate T Func1<out T>();      

static void Main(string[] args)      {          

   // Covariance           

   Func1<Cat> cat = () => new Cat();           

   Func1<Animal> animal = cat;           

}

}
 
La contravarianza tiende a ser más complicada de ilustrar. Aquí, se trata de sustituir el tipo derivado por el tipo base. Una de las situaciones donde a partir del Framework 4, se permite esta sustitución es en el paso de parámetros. La contravarianza se permite es en el paso de parámetros a diferencia de la covarianza que se permite en el retorno de tipos.
 
Ejemplo:
 
class Animal { }   

class Cat: Animal { }   

class Program    {     

delegate void Action1<in T>(T a);      

static void Main(string[] args)      {           

    // Contravariance           

             Action1<Animal> act1 = (ani) => { Console.WriteLine

                             (ani); };           

              Action1<Cat> cat1 = act1;           

           }
 
}
 
De nuevo, debido a que un Gato es un Animal, es esperable y deseable que los delegados que reciben parámetros de tipo Animal se puedan asignar a delegados que reciben Gatos como parámetro.
 
También, es posible, en Enumerados, utilizar las palabras in y out, en su definición, para lograr implementaciones de covarianza y contravarianza respectivamente. De hecho, en el Framework 4.0, ya la definición de la clase Enumerable<T> se modifica por Enumerable<Out T> y, por tanto, podemos tener este código:
 
IEnumerable<Cat> cats = new List<Cat>();
IEnumerable<Animal> animals = cats;
 
Es decir, podemos tener una covarianza, a nivel de enumerados.
 
De nuevo, esto es lo esperable y deseable, ya que como un Gato es un Animal se espera que un enumerado de gatos sea un enumerado de animales.
 
Otra forma de entender los conceptos de porque se llamarón covarianza y contravarianza, es dibujar flechas y asumir que la dirección de la flecha es la dirección del movimiento. Así:
 
En herencia tenemos una conversión de referencia implícita de Animal a Gato:
 
Animal → Gato
 
Y, como vimos, anteriormente, se permite en los enumerados, tener también un conversión de referencia implícita de IEnumerable<Animal> a IEnumerable<Gato>:
 
IEnumerable<Animal> → IEnumerable<Gato>
 
Se llama covarianza porque las flechas apuntan en la misma dirección o siguen el mismo movimiento.
 
En la contravarianza, la flecha va en el sentido contrario:
 
Animal → Gato
IComparable<Animal> ← IComparable<Gato>
 
En términos generales, se puede concluir que la covarianza y la contravarianza se refieren al uso de las palabras reservadas out e in respectivamente, en interfaces genéricas y delegados, para establecer relaciones entre tipos que mantienen la misma conversión de referencia implícita, que los tipos originales tenían en una relación de herencia (covarianza) o donde dicha conversión va en sentido inverso (contravarianza).

miércoles 16 de marzo de 2011

Dynamics en C#

 

Woow estuve leyendo acerca de las nuevas características que tiene C# para la versión 4 del Framework y me pareció excelente la inclusión de la palabra clave dynamic.
 
Esto permite, postergar, hasta el tiempo de ejecución , la evaluación de tipos. Es decir, en tiempo de compilación no se detectan errores de asignación de tipos.
 
La palabra dynamic permite indicarle al compilador que no efectúe la comprobación de asignación de tipos.
 
En el artículo que se encuentra aca:
http://msdn.microsoft.com/en-us/magazine/gg598922.aspx
 
Se hace una diferenciación clara de lo que son las definiciones con: object, var y dynamic.
 
var: Permite inferir el tipo, pero si hay un error en la asignación de tipos, el compilador lo detecta.
object: Tipo básico de todos los objetos de .NET siempre es necesario efectuar Cast, para hacer la asignación de tipos y que no se genere error en tiempo de compilación.
dynamic: Permite postergar la detección de errores por asignación de tipos hasta el tiempo de ejecución. En tiempo de compilación no se reportan errores.
 
Desde mi punto de vista de desarrollador y relacionado a lo que, normalmente, trabajo. Lo que más me gustó, en cuanto al uso de dynamic, es en los siguientes escenarios:
 
Interoperación con otros lenguajes o frameworks
 
Sin dynamic se tendría que acceder a la característica de Reflexión, para poder acceder a los métodos de un objeto o assembly, con el que se desee interactuar.
 
Ejemplo:
 
1.  object calc = GetCalculator();
2.  Type calcType = calc.GetType();
3.  object res = calcType.InvokeMember(
4.    "Add", BindingFlags.InvokeMethod,
5.    null, new object[] { 10, 20 });
6.  int sum = Convert.ToInt32(res);


Usando dynamic es más simple y fácil de comprender el código:
 
dynamic calc = GetCalculator();int sum = calc.Add(10, 20);
Agregar métodos dinámicamente a objetos
 
1.  dynamic expando = new ExpandoObject();2.  expando.SampleProperty = 3.    "This property was added at run time";4.  expando.SampleMethod = (Action)(5.    () => Console.WriteLine(expando.SampleProperty));6.  expando.SampleMethod();Interoperar con COM
 
Es decir, poder interoperar de una forma más fácil con Office, esta fue la meta de Microsoft al extender C# con dynamic y, en general, el framework DLR ( Dynamic Languaje Runtime)
 
Ejemplo:
 
1.  // Add this line to the beginning of the file:

2.  // using Excel = Microsoft.Office.Interop.Excel;

3.  

4.  var excelApp = new Excel.Application();

5.  

6.  excelApp.Workbooks.Add();

7.  // excelApp.Workbooks.Add(Type.Missing);

8.  

9.  excelApp.Visible = true;

10.

11.Excel.Range targetRange = excelApp.Range["A1"];

12.// Excel.Range targetRange = excelApp.get_Range("A1", Type.Missing);

13.

14.targetRange.Value = "Name";

15.// targetRange.set_Value(Type.Missing, "Name");

16.

17.targetRange.Columns[1].AutoFit();

18.// ((Excel.Range)targetRange.Columns[1, Type.Missing]).AutoFit();

En comentarios se encuentra la forma como se tenía que escribir, antes, el mismo código. La facilidad y mejora son innegables.