Hacer un Control que sea transparente

Problema

Una pregunta bastante común en los foros es tener dentro de un formulario un Panel o PictureBox, y que sea trasparente a la imagen de fondo establecida en el formulario.

Dentro de los colores de Fondo que podemos establecer dentro de uno de estos controles existe “Transparent”. Pero este color no es la solución, porque no va a coger el valor de la imagen, sino que va a coger el color de fondo del formulario.

Posible Solución, que no es la mejor.

Recogeremos la imagen de fondo, y capturaremos los pixeles para establecerlos al contenedor que queremos hacer transparente.

   1: void HacerTransparente(Bitmap original,Control control)

   2:         {

   3:             

   4:             Bitmap copiaPanel = new Bitmap(panel1.Width, panel1.Height);

   5:             for (int x = 0; x < panel1.Width; x++)

   6:             {

   7:                 for (int y = 0; y < panel1.Height; y++)

   8:                 {

   9:                     copiaPanel.SetPixel(x, y, original.GetPixel(x + panel1.Location.X, y + panel1.Location.Y));

  10:                 }

  11:             }

  12:             control.BackgroundImage = copiaPanel;

  13:         }

 

Espero que os resulte de utilidad.

 

Saludos!

[Opinión]Los Nuevos Programadores y VB o C#

Llevo relativamente poco tiempo en el mundo de la programación ya que mis orígenes, los verdaderos, serán del 2001 con C, aunque anteriormente ya había hecho cosas con Visual Basic 6.

Por si no lo he dicho nunca, o no me has leído decirlo me encanta programar.

Después de la primera introducción voy al hilo del post:

Aprender a programar: Me encanta que la gente se lance a aprender a programar y que tenga curiosidad por hacer sus propias aplicaciones, web, juegos, etcétera. Algo que es obvio es que nadie nace sabiendo, por lo que la mejor forma de aprender es a base de picar código, como cuando aprendimos a montar en bici que era a base de caerse.

Hoy en día, con Internet, es todo mucho más fácil, te conectas, abres tu buscador preferido y tecleas: “Código programa XXX para novato” y seguro que algún enlace te lleva a un foro como de la MSDN, o StackOverFlow…

¿Será que cada día nos estamos volviendo más vagos? La gente lo quiere ya todo mascado, es decir, no son capaces de investigar, de mirar la ayuda, de buscar un libro (Con los grandes libros de programación que existen), de buscar en Internet como se hace y no el código ya preparado para copiar y pegar. Muchas veces lo leo en los foros de MSDN, donde suelo colaborar de forma activa, y me cabree el poco hambre de aprender que tienen algunas personas.

La otra cuestión que está muy ligada al tema de los nuevos programadores es el lenguaje que adoptan si vienen a aprender con .NET.

Los dos grandes lenguajes del entorno de .NET son C# y VB.

Yo casi siempre he trabajado con VB y me encanta hacerlo, pero últimamente me estoy decantando en todos mis desarrollos por C# que me va ganando terreno.

Bien, a menudo, también, veo que mucha gente se decanta por aprender a trabajar con VB lo que me parece estupendo, ya que por internet es más fácil encontrar códigos de C#, pero también me digo: Mala Elección.

¿Por qué digo mala elección? Porque quizás trabajar con C# te fuerza a que intentes hacer las cosas bien desde el primer momento. Algunos ejemplos:

– VB permite conversiones sin indicar ninguna (Option Strict) C# no lo permite.

– VB permite manejar formularios de la misma manera que se hacia en VB6, es decir, sin instanciarlos.

Se que estos y muchos puntos que no escribo, son puntos que la gente debería conocer, pero cuando estás aprendiendo a programar, no te paras en esos detalles, quieres tirar líneas de código y que funcione.

Por eso, quizás si alguien me pidiera consejo para aprender un lenguaje de programación entre C# y VB le diría que aprenda C#. Porque además, el poder saltar luego a VB es un salto relativamente sencillo.

 

Saludos!!!

[EF] Ampliar la plantilla por defecto

Aunque tengo algunos post pendientes acerca de mi serie de EF, esta semana he podido sacar un rato para este post que creo que puede resultar interesante.

Objetivo

Lo que planteo es ampliar el código definido en la plantilla T4 que se utiliza al generar los objetos de Entity Framework:

Comenzando

Hasta el momento, en todos los post que he escrito, estaba utilizando el modelo estándar, así que voy a explicar como dejar de utilizar esa plantilla para utilizar otra distinta:

-> Pulsamos, dentro del diseñador de nuestro modelo, con el botón secundario del ratón:

 

-> En el menú, elegiremos la opción Add Códe Generation Item. A continuación aparecerá el siguiente cuadro de dialogo:

En dicho cuadro, elegiremos la Opción “ADO .NET EntityObject Generator” y presionaremos Add.

La Plantilla

Dentro de nuestro proyecto de Visual Studio se habrá añadido un fichero con la extensión TT. Este tipo de ficheros son Plantillas de Generación de Código T4.

Esta plantilla va a contener el código necesario para generar la estructura del contexto y de las entidades de nuestro modelo, así como las relaciones entre las mismas.

Si revisáis el enlace al que hago referencia, explico como incrustar bloques de texto, bloques de código y funciones, por ello no voy a entrar a definirlo.

Modificando la Plantilla

Lo que me gustaría añadir a la plantilla es una forma de garantizar que las propiedades del objeto que no admiten valores Nulos, no tienen un valor nulo, antes de intentar Agregarlo al conjunto de datos al que hacen referencia.

Para lograrlo, vamos a hacer uso de “Reflection”  y de un método extensor que agregará funcionalidad a los objetos de tipo “EntityObject”.

Paso 1:

Localizar dentro de la Plantilla “.tt”, la sección donde se escriben los “using / imports” y agregar la referencia al namespace “System.Reflection”

   1: using System.Reflection;

Paso 2:

Definir el método extensor dentro del NameSpace que se va a generar dentro de la plantilla. Para poder localizarlo, podremos buscar dentro de la plantilla el literal “namespace <#=namespaceName#>”.

   1: public static class EntityExtensions

   2: {

   3:     public static bool CheckNullableValues(this EntityObject entity)

   4:     {

   5:         bool retValue = true;

   6:         foreach (PropertyInfo p in entity.GetType().GetProperties())

   7:         {

   8:             foreach (Attribute atr in p.GetCustomAttributes(true))

   9:             {

  10:                 if (atr.GetType().Equals(typeof(EdmScalarPropertyAttribute)))

  11:                 {

  12:                     if (!(atr as EdmScalarPropertyAttribute).IsNullable)

  13:                     {

  14:                         if (p.GetValue(entity, BindingFlags.ExactBinding, null, null, 

  15:                             System.Threading.Thread.CurrentThread.CurrentCulture) == null)

  16:                             return false;

  17:                     }

  18:                 }

  19:  

  20:             }

  21:             

  22:         }

  23:         return retValue;

  24:     }

  25: }

Este método extensor se va a encargar de recorrer las propiedades de la Entidad y comprobar si tiene el atributo “EdmScalarPropertyAttribute” y si su valor es “nullable” es falso.

Paso 3:

Por último, será necesario que encontremos los métodos AddTo, que serán los encargados de agregar las entidades a sus relativos conjuntos.

Para poder encontrar dicho bloque de código, podremos buscar la cadena: “void AddTo<#=set.Name#>”

El código de esa función al momento de definir la plantilla es:

   1: base.AddObject("<#=set.Name#>", <#=parameterName#>);

El código después de modificarlo será:

 

   1: if (<#=parameterName#>.CheckNullableValues())

   2:             base.AddObject("<#=set.Name#>", <#=parameterName#>);

   3:         else

   4:             throw new Exception(String.Format("Falta rellenar alguna propiedad del objeto {0}",

   5:                                 <#=parameterName#>.ToString()));

 

Una vez modificado, estos bloques de código, cuando visualicemos el fichero “cs” generado podremos encontrar métodos como el siguiente:

   1: public void AddToCLIENTES(CLIENTES cLIENTES)

   2:         {

   3:             if (cLIENTES.CheckNullableValues())

   4:                 base.AddObject("CLIENTES", cLIENTES);

   5:             else

   6:                 throw new Exception(String.Format("Falta rellenar alguna propiedad del objeto {0}",

   7:                 cLIENTES.ToString()));

   8:         }

 

Conclusiones

Las plantillas de generación de código nos pueden ayudar a incrementar la funcionalidad de Entity Framework.

 

Espero que os haya gustado y os motive a investigar las plantillas T4.

 

Saludos

[TIP] Obtener Nombres o Descripciones de un Enumerado (Avanzado)

Después de haber publicado Obtener Nombres de un Enumerado, Pablo Nuñez(@pablonete), me ha lanzado una pregunta:

"¿Has probado [Description("x")] en los enum?”

 

¿Qué es Description?

Es un atributo que nos permite dar una descripción a un miembro del código.

 

Bien dejando de lado la definición, el enunciado sería:

Mostrar la Descripción de los miembros de la enumeración, si existen.

Para poder lograrlo, he tenido que recurrir al NameSpace System.Reflection gracias al cual he visto como obtener todas los datos que requeria.

Para comenzar el ejemplo he creado un pequeño modulo:

C#

   1: using System.ComponentModel;

   2:         enum miEnum

   3:         {

   4:             [Description("Elemento 1")]

   5:             valor1,

   6:             [Description("Elemento 2")]

   7:             valor2,

   8:             valor3

   9:         }

VB

   1: Imports System.ComponentModel

   2: Public Enum MiEnum

   3:     <Description("Elemento 1")> _

   4:      Valor1

   5:     <Description("Elemento 2")> _

   6:     Valor2

   7:     Valor3

   8: End Enum

He creado una función que es la que va obtener dicho atributo, y en caso de que no exista devolverá el valor del Nombre (como en el post anterior).

 

C#

   1: private Dictionary<int,string> GetListDesc(Type tipoEnum)

   2: {

   3: Dictionary<int,string> lValores=new Dictionary<int,string>();

   4:     string key="";

   5:     int valorNum=0;

   6:     foreach (var valor in Enum.GetValues(tipoEnum))

   7:     {

   8:        var query=valor.GetType().

   9:            GetField(valor.ToString()).GetCustomAttributes(true).

  10:            Where(a=> a.GetType().Equals(typeof(System.ComponentModel.DescriptionAttribute)));

  11:         valorNum=Convert.ToInt32(valor);

  12:         if (query.Any())

  13:         {

  14:             key=(valor.GetType().

  15:                 GetField(valor.ToString()).GetCustomAttributes(true).

  16:                 Where(a=> a.GetType().Equals(typeof(System.ComponentModel.DescriptionAttribute))).

  17:                 FirstOrDefault() as System.ComponentModel.DescriptionAttribute).Description;                }

  18:         else

  19:         {

  20:             key = Enum.GetName(tipoEnum, valor);

  21:         }

  22:         lValores.Add(valorNum,key);

  23:     }

  24:     return lValores;

  25: }

VB

 

   1: Private Function GetListDesc(ByVal tipoEnum As Type) As Dictionary(Of Integer, String)

   2:  

   3:     Dim lValores As New Dictionary(Of Integer, String)

   4:  

   5:     For Each valor In [Enum].GetValues(tipoEnum)

   6:         If valor.GetType().GetField(valor.ToString()).

   7:             GetCustomAttributes(True).

   8:             Where(Function(a) a.GetType().

   9:                       Equals(GetType(System.ComponentModel.DescriptionAttribute))).Any() Then

  10:             lValores.Add(valor, valor.GetType().

  11:                          GetField(valor.ToString()).

  12:                          GetCustomAttributes(True).

  13:                          Where(Function(a) a.GetType().

  14:                                    Equals(GetType(System.ComponentModel.DescriptionAttribute))).

  15:                                FirstOrDefault().Description)

  16:         Else

  17:             lValores.Add(valor, [Enum].GetName(tipoEnum, valor))

  18:         End If

  19:     Next

  20:  

  21:     Return lValores

  22: End Function

 

Y para invocarlas:

C#

   1: Dictionary<int, string> miEnum = new Dictionary<int, string>();

   2:  

   3:             var query = (from int n in Enum.GetValues(typeof(System.Windows.Forms.DialogResult))

   4:                         select new {

   5:                             n,

   6:                             Valor = GetListDesc(typeof(miEnum)).FirstOrDefault(a => a.Key == n).Value

   7:                             

   8:                         });

   9:  

  10:             comboBox1.DataSource = query.ToList();

  11:             comboBox1.DisplayMember = "Valor";

  12:             comboBox1.ValueMember = "n";

VB

 

   1: Dim query = From n As Integer In [Enum].GetValues(GetType(MiEnum))

   2:             Select New With {n, .Valor = GetListDesc(GetType(MiEnum)).

   3:             Where(Function(a) a.Key = n).FirstOrDefault().Value}

   4:  

   5: ComboBox1.DataSource = query.ToList()

   6: ComboBox1.DisplayMember = "Valor"

 

Espero que os sea de utilidad y si tenéis dudas aquí estoy.

Saludos.

[TIP] Obtener los Nombres de un Enumerado

El objeto de este post es explicar como devolver los datos de un enumerado para poder trabajarlos o mostrarlos por ejemplo en un ComboBox.

Como el código vale más que mil palabras, aquí van dos ejemplos en C# y VB:

C#

   1: var query = (from int n in Enum.GetValues(typeof(System.Windows.Forms.DialogResult))

   2:             select new {

   3:                 n,

   4:                 Key = Enum.GetName(typeof(System.Windows.Forms.DialogResult),n)

   5:                 

   6:             });

   7:  

   8: comboBox1.DataSource = query.ToList();

   9: comboBox1.DisplayMember = "key";

  10: comboBox1.ValueMember = "n";

 

VB

   1: Dim query = From n As Integer In [Enum].GetValues(GetType(DialogResult))

   2:             Select New With {n, .Valor = [Enum].GetName(GetType(DialogResult), n)}

   3:  

   4: ComboBox1.DataSource = query.ToList()

   5: ComboBox1.DisplayMember = "Valor"

   6: ComboBox1.ValueMember = "n"

 

En el caso del ejemplo estoy obteniendo los nombres de la enumeración DialogResult, pero se puede utilizar cualquier enumeración existente o propia.

Espero que os sea de utilidad.

Saludos!