Ya tengo la estrella de oro!!!

Hola chic@s,


Pues sí, hace un rato acabo de aprobar el último exámen que me quedaba. He aprobado todos a la primera excepto el de ADO Entity Framework que lo he aprobado a la segunda, pero si hace unos días os comentaba que el exámen de SQL Server 2008 solo tenía 14 preguntas, el resto ha resultado tener 20 preguntas como siempre, pero cuando suspendí el de Entity siendo la puntuación negativa, la aplicación me felicitaba como si hubiera aprobado. Lo importante es que ya me he quitado este peso de encima y ahora a esperar a que salga la de platino.



 Un saludo.

A por la estrella de oro

Hola a tod@s,


Aunque hace ya un tiempecito, el programa «Desarrollador 5 Estrellas 2005» anunciaba que ya estaba disponible la estrella de oro, yo lo dejé aparcado porque la 5º estrella me llevó su tiempo y ultimamente estoy apurada, pero hoy he vuelto con mas fuerzas que nunca y mi primera elección ha sido prepararme el exámen de «Desarrollo para SQL Server 2008» y puedo decir muy satisfecha que lo he aprobado, pero que por poco me da un síncope ya que mientras que estaba haciendo el exámen indicaba que había 20 preguntas para contestar (igual que el resto de exámenes) pero cuando he llegado a la pregunta 14 me ha salido el botón de finalizar, lo que me ha hecho pensar que puntuaba como si fueran 20 preguntas y te termina el exámen con 14 lo que te obliga a contestar todo correctamente, pero no, esta vez parece que puntua sobre 14. Mañana seguiré por el de Entity Framework, a ver si me resulta tan fácil como el de SQL.


Para el que no lo sepa, la estrella de oro consiste en aprobar 4 exámenes, ADO.NET Entity Framework, Desarrollo para SQL Server 2008, dispositivos moviles con Windows Mobile 6.0 y Desarrollo con Sharepoint 2007.


Un saludo.

Infragistics – Ultragrid (Parte II)

Hola a tod@s,


Siguiendo con la serie de Infragistics – Ultragrid, hoy os voy a mostrar un ejemplo de como podemos crear dos columnas de tipo dropdownlist en un grid y que los datos de la segunda columna dependa del elegido en la primera en una aplicación de escritorio.


Para el ejemplo voy a usar la base de datos AdventureWorks para SQL Server 2005 Express, y la versión de Infragistics 7.3 para CLR2 con VS2005.


Creamos una aplicación Windows Forms en C#. Arrastramos desde la toolbox un objeto UltraGrid.


En el evento Load del form rellenamos dos Infragistics.Win.ValueList, el primero de ellos con datos de la tabla Product, cuyo valor será ProductID y el texto será Name, para el segundo lo rellenamos con los datos de ProductInventory, cuyo valor será LocationID y el texto será una composición de los campos Shelf, Bin y Quantity (para saber lo que significa cada campo ver el diccionario de datos de AdventureWorks). Luego nos creamos un datatable con dos columnas ProductID y LocationID y la rellenamos tal y como se vé en el código. Este datatable será el proveedor de datos del Ultragrid. Luego asociamos los valuelist a cada columna.





  private void Form1_Load(object sender, EventArgs e)
        {
            SqlConnectionStringBuilder strCon = new SqlConnectionStringBuilder();
            strCon.IntegratedSecurity = true;
            strCon.DataSource = «CSANCHEZG»;
            strCon.InitialCatalog = «AdventureWorks»;
            Infragistics.Win.ValueList val = new Infragistics.Win.ValueList();
            Infragistics.Win.ValueList val2 = new Infragistics.Win.ValueList();
            DataTable dt = new DataTable();

           
using (SqlConnection con = new SqlConnection(strCon.ConnectionString))
            {
                using (SqlCommand cmd = new SqlCommand(«SELECT ProductID, Name FROM Production.Product»))
                {
                    cmd.Connection = con;
                    SqlDataReader dr;
                    con.Open();
                    dr = cmd.ExecuteReader();

                    while (dr.Read())
                    {
                        val.ValueListItems.Add(dr[0], dr[1].ToString());
                    }
                    con.Close();
                }

                using (SqlCommand cmd = new SqlCommand(«Select LocationID, ‘Shelf: ‘ + Shelf + ‘, Bin: ‘ + Cast(Bin as varchar) + ‘, Quantity: ‘ + Cast(Quantity as varchar) from Production.ProductInventory»))
                {
                    cmd.Connection = con;
                    SqlDataReader dr;
                    con.Open();
                    dr = cmd.ExecuteReader();

                    while (dr.Read())
                    {
                        val2.ValueListItems.Add(dr[0], dr[1].ToString());
                    }
                    con.Close();
                }
            }
            
            dt.Columns.Add(«ProductID», typeof(Int32));
            dt.Columns.Add(«LocationID», typeof(Int32));

            DataRow drow;
            for (int i = 1; i < 5; i++)
            {
                drow = dt.NewRow();
                drow[0] = i;
                drow[1] = System.DBNull.Value;
                dt.Rows.Add(drow);
            }
            dt.AcceptChanges();

            ultraGrid1.DataSource = dt;
            ultraGrid1.DataBind();
            ultraGrid1.DisplayLayout.Bands[0].Columns[0].Style = Infragistics.Win.UltraWinGrid.ColumnStyle.DropDownList;
            ultraGrid1.DisplayLayout.Bands[0].Columns[0].ValueList = val;
            ultraGrid1.DisplayLayout.Bands[0].Columns[0].MinWidth = 200;

           
ultraGrid1.DisplayLayout.Bands[0].Columns[1].Style = Infragistics.Win.UltraWinGrid.ColumnStyle.DropDownList;
            ultraGrid1.DisplayLayout.Bands[0].Columns[1].ValueList = val2;
            ultraGrid1.DisplayLayout.Bands[0].Columns[1].MinWidth = 200;

         }


Para que cuando pulsemos en el segundo combo que depende del dato elegido en el primer combo, usamos el evento del Ultragrid AfterRowActivate para que el valuelist asociado al segundo combo se rellene dependiendo del valor seleccionado en el primer combo.





         private void ultraGrid1_AfterRowActivate(object sender, EventArgs e)
        {
            Infragistics.Win.ValueList val2 = new Infragistics.Win.ValueList();
            SqlConnectionStringBuilder strCon = new SqlConnectionStringBuilder();
            strCon.IntegratedSecurity = true;
            strCon.DataSource = «CSANCHEZG»;
            strCon.InitialCatalog = «AdventureWorks»;

            try
            {
                if ( ! Equals(ultraGrid1.ActiveRow.Cells[«LocationID»].Column.ValueList, null))
                {
                    using (SqlConnection con = new SqlConnection(strCon.ConnectionString))
                    {
                         using (SqlCommand cmd = new SqlCommand(«Select LocationID, ‘Shelf: ‘ + Shelf + ‘, Bin: ‘ + Cast(Bin as varchar) + ‘, Quantity: ‘ + Cast(Quantity as varchar) from Production.ProductInventory » +
                                                               «WHERE ProductID=» + (int)ultraGrid1.ActiveRow.Cells[«ProductID»].Value))
                        {
                            cmd.Connection = con;
                            SqlDataReader dr;
                            con.Open();
                            dr = cmd.ExecuteReader();

                            while (dr.Read())
                            {
                                val2.ValueListItems.Add(dr[0], dr[1].ToString());
                            }
                            con.Close();
                        }
                    }

                    ultraGrid1.ActiveRow.Cells[«LocationID»].Value = System.DBNull.Value;
                    ultraGrid1.ActiveRow.Cells[«LocationID»].ValueList = val2;
                }
            }
            catch (Exception ex)
            {
            }
        }


Y para que nuestro segundo combo se actualice cuando seleccionamos un nuevo valor en el primer combo podemos usar el evento CellListSelect.





        private void ultraGrid1_CellListSelect(object sender, Infragistics.Win.UltraWinGrid.CellEventArgs e)
        {
            SqlConnectionStringBuilder strCon = new SqlConnectionStringBuilder();
            strCon.IntegratedSecurity = true;
            strCon.DataSource = «CSANCHEZG»;
            strCon.InitialCatalog = «AdventureWorks»;

            try{
                if (! Equals(e.Cell.Column.ValueList, null))
                {
                    if (e.Cell.Column.Key == «ProductID» && e.Cell.Column.ValueList.SelectedItemIndex >= 0 )
                    {
                        Infragistics.Win.ValueList val = new Infragistics.Win.ValueList();
                        Infragistics.Win.ValueListItem item = new Infragistics.Win.ValueListItem();

                       
item = val.ValueListItems[e.Cell.Column.ValueList.SelectedItemIndex];
   

                       
using (SqlConnection con = new SqlConnection(strCon.ConnectionString))
                        {
                             using (SqlCommand cmd = new SqlCommand(«Select LocationID, ‘Shelf: ‘ + Shelf + ‘, Bin: ‘ + Cast(Bin as varchar) + ‘, Quantity: ‘ + Cast(Quantity as varchar) from Production.ProductInventory « +
                                                                   «WHERE ProductID=» + (int)item.DataValue))
                            {
                                cmd.Connection = con;
                                SqlDataReader dr;
                                con.Open();
                                dr = cmd.ExecuteReader();

                                while (dr.Read())
                                {
                                    val.ValueListItems.Add(dr[0], dr[1].ToString());
                                }

                                con.Close();
                             }
                        }

                        ultraGrid1.ActiveRow.Cells[«LocationID»].Value = System.DBNull.Value;
                        ultraGrid1.ActiveRow.Cells[«LocationID»].ValueList = val;
                     }
                }
            }
            catch (Exception ex)
            {}

        }


Espero les resulte útil.


Un saludo.

Nueva funcionalidad Crystal Reports 2008

Hola a tod@s,


Estoy haciendo la migración de informes hechos con Crystal Reports XI a 2008 y me he encontrado con un caso en que he tenido que rehacer el informe, lo curioso es que cuando estaba haciendo una agrupación me he fijado en las opciones de los grupos.







 

Crystal Reports XI
 

Crystal Reports 2008


Ahora se puede decir que cada grupo aparezca en una página distinta desde las opciones de los grupos y no como antes que había que hacerlo en los detalles de las secciones.


Un saludo.

Ejemplo Validación con Enterprise Library en aplicación Windows (parte II)

 Hola a tod@s,

Os dejo con la segunda parte del artículo «Ejemplo Validación con Enterprise Library en aplicación Windows», este también está traído de mi antiguo blog.

Para finalizar con el ejemplo de aplicando validaciones con Enterprise Library, ahora os voy a explicar como implementarlo desde el app.config, de tal forma que si cambian no tengamos que volver a recompilar la solución, simplemente modificando el XML del archivo de configuración nos baste, ¿a que es guapísimo?


Los pasos que he seguido son:

1º. Agregar una nuevo proyecto de librerías de clases a la solución que tenía. Lo he llamado Prueba.
2º. Al proyecto prueba le he añadido una clase que he llamado NewEmployee, y le he definido las mismas propiedades que la clase Employee, pero sin añadirle validaciones.

1

3º. He compilado el nuevo proyecto, y lo he referenciado al primero ELValidation.
4º. Ahora con boton derecho sobre el App.Config pulsamos en «Edit Enterprise Library Configuration»

2

5º. Nos aparece el App.Config editado de la siguiente forma.

3

6º. Con botón derecho sobre la ruta completa del App.Config podemos agregar nuevos elementos de los application Block. Para el ejemplo que estamos haciendo, un Validation Application Block.

4

Cuando aparece desactivado el menú, es porque ya lo tenemos agregado en el App.Config, como podéis observar en el dibujo.

7º. Ahora con botón derecho sobre «Validation Application Block» agregamos un nuevo Type. Como podréis observar nos salen un montón de tipos excepto el que nos interesa que es nuestro proyecto Prueba. Para eso hay que pulsar en «Load an Assembly», y buscamos nuestro Assembly «Prueba»

5 
6

8º. Ahora podemos elegir «Prueba» como nuestro Type. Os aviso de que cuando se carga un nuevo Assembly, luego el resto de Assemblies que había se expanden y es un poco costoso encontrar el que queremos. Con paciencia vamos contrayendo los assemblies que no nos interesan hasta que llegamos al de nuestro ejemplo, en este caso el Assembly «Prueba» tiene un NameSpace «Prueba» y dentro de él la clase «NewEmployee» que queremos validar.

7

9º. Una vez que tenemos en la edición del App.Config la clase que queremos validar con botón derecho sobre ella elegimos nuevo «RuleSet», le podemos cambiar el nombre a lo que queremos. Ahora con botón derecho sobre el conjunto de reglas elegimos nuevo «Choose Members», nos aparece una nueva ventana con todas las propiedades y métodos de la clase, si pinchamos sobre el check de Properties nos selecciona todas.

8

10º. Ahora con botón derecho sobre cada propiedad podemos ir añadiendo validadores, o carpetas de validadores «and» o «or» para poner varias condiciones a la vez. Como muestro en las siguientes imágenes, podemos añadir validadores de no nulidad, de longitud de cadena, expresiones regulares, de fechas y customizados.

9
En esta imagen he añadido a cada propiedad dos validadores, uno de no nulidad y otro de cadena, fecha, expresion regular o customizado según el caso, excepto para la propiedad LastName que solo he dejado una única validación de cadena. Es lo mismo que tenía en el artículo anterior mediante código para la clase Employee.


10
Como vemos en al imagen, el valor de no nulidad es bastante sencillito, le podemos nombrar como queramos, y para mostrar el texto cuando se produce la excepción de validación, lo podemos hacer mediante la propiedad MessageTemplate si no vamos a tener multi idioma, o con un fichero de recursos, en mi caso como quiero multi idioma lo he hecho con el fichero de recursos, simplemente hay que especificar el nombre de la cadena del fichero de recursos de la que extrae el mensaje gracias a la propiedad MessageTemplateResourceName, y donde se encuentra el fichero de recursos gracias a la propiedad MessageTemplateResourceTypeName, en este caso es «ELValidation.Resource1, ElValidation», es decir, «NameSpace.Clase, NameSpace». El Visual Studio también nos permite encontrar el fichero de recursos pulsando en 15 cuando nos posicionamos en la propiedad, sería encontrar el Assembly donde está y seleccionarlo.


11
Para los validadores de cadena, simplemente es poner el valor menor y el máximo teniendo en cuenta si queremos que se validen incluso esos valores mediante las propiedades LowerBoundType y UpperBoundType respectivamente. El mensaje a mostrar funciona exactamente en todos los validadores de la misma manera que lo que he explicado en el validador no nulo.


12
Lo mismo para las fechas, podemos elegir un valor mínimo y uno máximo, decidir si queremos que sea el año, el mes, el día o la fecha entera la que se validad.


13
También podemos validar mediante expresiones regulares, e incluso tener un fichero de recursos con el patrón a seguir.


14 
También podemos crearnos nuestros propios validadores. A esto tengo que comentar que he tenido que modificar ligeramente la clase NifValidator para que me funcione con respecto a lo que tengo en el artículo anterior.
He modificado el primer construtor de la clase NifValidator para que quede:
public NifValidator(NameValueCollection attributes)
            : base(null, null)
        {
        }

También he tenido que modificar la clase NifValidatorAttribute cambiando la llamada al constructor de NifValidator en el método DoCreateValidator quedando:
protected override Validator DoCreateValidator(Type targetType)
        {
            return new NifValidator(null, null);
        }

11º. Ahora solo nos queda modificar el ValidatorProvider del formulario Form1 para que mire en el App.Config

16

También he modificado el evento Load del formulario para crearme un objeto de tipo NewEmployee, que sus propiedades se rellenen con lo que inserto en las cajas de texto y ya estaría.

           NewEmployee otroEmpleado = new NewEmployee(); //Como variable de clase

            //Esta parte estaría en el Load del formulario
            otroEmpleado.Code = txtCode.Text;
            otroEmpleado.Nif = txtNIF.Text;
            otroEmpleado.FirstName = txtFirstName.Text;
            otroEmpleado.LastName = txtLastName.Text;
            otroEmpleado.DateOfBirth = dtpDateOfBirth.Value;
            otroEmpleado.Email = txtEmail.Text;

           //Este código iría en el botón de validar
           if (otroEmpleado != null)
            {
                vpEmployee.Enabled = true;
                this.ValidateChildren();
            }

Al final el formulario tiene que quedar así si no se introduce ningún dato y lo hemos validado

17

Sería un buen ejercicio que a apartir de las fuentes que he dejado en el artículo anterior, el que tenga interés en el tema, intente reproducir la situación que he comentado en este artículo.

Espero que os haya servido.

Saludos.

Infragistics – UltraGrid (parte I)

Hola a tod@s,


Después de llevar bastantes meses (desde mi antiguo blog) prometiendo escribir sobre los controles de Infragistics voy a comenzar con un pequeño ejemplo de cómo rellenar un UltraGrid por código y darle algo de formato y funcionalidad.


Para el ejemplo voy a asar la base de datos AdventureWorks para SQL Server 2005 Express, y la versión de Infragistics 7.3 para CLR2 con VS2005.


Creamos una aplicación Windows Forms en C#. Arrastramos desde la toolbox un objeto UltraGrid


NOTA: Para tener los objetos de Infragistics en la barra de herramientas lo podemos hacer de forma tradicional (que no es muy idónea en este caso) o ejecutar la herramienta “Create Visual Studio Toolbox Tab” como muestro en la imagen:



Esto hace que nos aparezca una nueva pestaña en nuestra barra de herramientas con los controles de infragistics.


Cuando arrastramos un control UltraGrid en un formulario nos aparece un asistente para formatear el grid, pero para este ejemplo pulsamos en el botón finish y ponemos su propiedad Dock a Fill



Ahora en el evento Load del formulario accedemos a base de datos y rellenamos un DataTable para luego asociarlo al grid. Nos quedará algo como esto:





private DataTable dtDatos = new DataTable();

private void Form1_Load(object sender, EventArgs e)       

{

            SqlConnectionStringBuilder strCon = new SqlConnectionStringBuilder();
            strCon.IntegratedSecurity = true;
            strCon.DataSource = «CSANCHEZG»;
            strCon.InitialCatalog = «AdventureWorks»;
            using (SqlConnection con = new SqlConnection(strCon.ConnectionString))
            {
                using (SqlDataAdapter da = new SqlDataAdapter(«SELECT * FROM Production.Product», con))
                {
                    da.Fill(dtDatos);
                }
            }

           
ultraGrid1.DataSource = dtDatos;
            ultraGrid1.DataBind();

            FormateoGrid();

        }


Como podemos observar en el código, tenemos la llamada a un método que va a formatear nuestro grid, el código del método será:





private void FormateoGrid(){
            ultraGrid1.DisplayLayout.Override.AllowRowFiltering = Infragistics.Win.DefaultableBoolean.True;
            ultraGrid1.DisplayLayout.GroupByBox.Prompt = «Arrastra aquí alguna cabecera para agrupar por ella»;
            ultraGrid1.DisplayLayout.Override.RowSelectorHeaderStyle = Infragistics.Win.UltraWinGrid.RowSelectorHeaderStyle.ColumnChooserButton;           
            ultraGrid1.DisplayLayout.Override.RowSelectors = Infragistics.Win.DefaultableBoolean.True;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ProductID»].Hidden=true;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ProductID»].ExcludeFromColumnChooser = Infragistics.Win.UltraWinGrid.ExcludeFromColumnChooser.True;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«Name»].Header.Caption = «Nombre»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ProductNumber»].Header.Caption = «Número del Producto»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«MakeFlag»].Hidden = true;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«MakeFlag»].ExcludeFromColumnChooser = Infragistics.Win.UltraWinGrid.ExcludeFromColumnChooser.True;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«FinishedGoodsFlag»].Hidden = true;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«FinishedGoodsFlag»].ExcludeFromColumnChooser = Infragistics.Win.UltraWinGrid.ExcludeFromColumnChooser.True;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«Color»].Hidden = true;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«Color»].Header.Caption = «Color»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«SafetyStockLevel»].Header.Caption = «Cantidad mínima del inventario»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ReorderPoint»].Hidden = true;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ReorderPoint»].Header.Caption = «Nivel del inventario»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«StandardCost»].Hidden = true;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«StandardCost»].Header.Caption = «Costo estándar»;            ultraGrid1.DisplayLayout.Bands[0].Columns[«ListPrice»].Hidden = true;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ListPrice»].Header.Caption = «Precio de Venta»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«Size»].Header.Caption= «Tamaño»;
           
ultraGrid1.DisplayLayout.Bands[0].Columns[«SizeUnitMeasureCode»].Header.Caption = «Unidad de Medida del Tamaño»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«WeightUnitMeasureCode»].Header.Caption = «Unidad de Medida del Peso»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«Weight»].Header.Caption = «Peso»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«DaysToManufacture»].Header.Caption = «Dias para crearlo»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ProductLine»].Header.Caption = «Linea del Producto»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«Class»].Hidden = true;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«Class»].Header.Caption = «Clase»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«Style»].Hidden = true;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«Style»].Header.Caption = «Estilo»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ProductSubcategoryID»].Hidden = true;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ProductSubcategoryID»].Header.Caption = «Subcategoria del producto»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ProductModelID»].Hidden = true;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ProductModelID»].Header.Caption = «Modelo»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«SellStartDate»].Header.Caption = «Fecha inicio venta»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«SellEndDate»].Header.Caption = «Fecha find venta»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«DiscontinuedDate»].Header.Caption = «fecha de discontinuidad»;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«rowguid»].Hidden = true;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«rowguid»].ExcludeFromColumnChooser = Infragistics.Win.UltraWinGrid.ExcludeFromColumnChooser.True;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ModifiedDate»].ExcludeFromColumnChooser = Infragistics.Win.UltraWinGrid.ExcludeFromColumnChooser.True;
            ultraGrid1.DisplayLayout.Bands[0].Columns[«ModifiedDate»].Hidden = true;
         } 

La propiedad ultraGrid1.DisplayLayout.Override.AllowRowFiltering hace que nos aparezcan unos botones en la cabecera los cuales nos dan la posibilidad de filtrar.



Las propiedades ultraGrid1.DisplayLayout.Override.RowSelectorHeaderStyle = Infragistics.Win.UltraWinGrid.RowSelectorHeaderStyle.ColumnChooserButton; y
            ultraGrid1.DisplayLayout.Override.RowSelectors = Infragistics.Win.DefaultableBoolean.True; nos dan la posibilidad de que podamos elegir las columnas que queremos mostrar u ocultar con un botón a la izquierda de la cabecera.







La propiedad ultraGrid1.DisplayLayout.GroupByBox.Prompt = «Arrastra aquí alguna cabecera para agrupar por ella»; nos permite (tal y como se ve) poner el texto que queramos, por defecto es un texto en inglés.


Para cada columna he usado las siguientes propiedades:

Hidden:  hace que el campo no aparezca, pero no quiere decir que no aparezca en el selector de columnas.
ExcludeFromColumnChooser : esta propiedad hace que no aparezca en el selector de columnas con lo que si el campo es visible, el usuario nunca podrá ocultarlo y si es invisible, el usuario nunca lo podrá ver.
Header.Caption : es el texto de la cabecera de cada columna.


Hay muchísimas propiedades que si os interesa podéis ir investigando.


Y para acabar el ejemplo, quiero que cuando el tamaño sea “XL” el fondo de la fila se muestre en rojo con un degradado. Para ello uso el evento InitializeRow del UltraGrid





private void ultraGrid1_InitializeRow(object sender, Infragistics.Win.UltraWinGrid.InitializeRowEventArgs e)
        {
            if (e.Row.Cells[«Size»].Value.ToString().Trim() == «XL»)
            {
                e.Row.Appearance.BackColor = Color.Red;
                e.Row.Appearance.BackColor2 = Color.White;
                e.Row.Appearance.BackGradientStyle = Infragistics.Win.GradientStyle.Vertical;
            }
        }


Espero que les haya interesado el artículo.


Saludos.

Ejemplo Validación con Enterprise Library en aplicación Windows

Este es un artículo que me traigo a geeks de mi antiguo blog.


 

En el siguiente artículo expongo con un ejemplo muy sencillo como implementar en una aplicación de escritorio validaciones con las Enterprise Library de Microsoft (versión 3.1 Mayo 2007). El ejemplo está hecho en C# y os podéis bajar el código fuente aquí.

 

Creamos un nuevo proyecto de Windows Application, en mi caso lo he llamado ELValidation. Le añadimos las referencias de Microsoft.Practices.EnterpriseLibrary.Common, Microsoft.Practices.EnterpriseLibrary.Validation y Microsoft.Practices.EnterpriseLibrary.Validation.Integration.WinForms.

 

En el ejemplo que he creado tengo una clase que representa a un empleado («Employee.cs»), en la que defino sus propiedades. Es aquí donde mediante atributos en las propiedades le vamos asignando las validaciones.

 

        private string code;
        private string nif;
        private string firstName;
        private string lastName;
        private DateTime dateOfBirth;
        private string email;

        [StringLengthValidator(1, 10, Ruleset = «RuleSet1″, MessageTemplateResourceName=»InvalidCodeMessage», MessageTemplateResourceType=typeof(Resource1))]
        public virtual string Code
        {
            get { return code; }
            set { code = value; }
        }
        [NifValidator(Ruleset = «RuleSet1″, MessageTemplateResourceName=»InvalidNifMessage», MessageTemplateResourceType=typeof(Resource1))]
        public virtual string Nif
        {
            get { return nif; }
            set { nif = value; }
        }

        [RelativeDateTimeValidator(-120, DateTimeUnit.Year, -16, DateTimeUnit.Year, Ruleset = «RuleSet1», MessageTemplateResourceName = «InvalidBirthMessage», MessageTemplateResourceType = typeof(Resource1))]
        public DateTime DateOfBirth
        {
            get { return dateOfBirth; }
            set { dateOfBirth = value; }
        }

        [ValidatorComposition(CompositionType.And, Ruleset = «RuleSet1»)]
        [RegexValidator(@»w+([-+.’]w+)*@w+([-.]w+)*.w+([-.]w+)*», MessageTemplateResourceName = «InvalidEmailMessage2», MessageTemplateResourceType = typeof(Resource1), Ruleset = «RuleSet1»)]
        [StringLengthValidator(1, 100, Ruleset = «RuleSet1», MessageTemplateResourceName = «InvalidEmailMessage1», MessageTemplateResourceType = typeof(Resource1))]
        public string Email
        {
            get { return email; }
            set { email = value; }
        }

Como podemos observar en el código, tengo varios tipos de validaciones, para la propiedad Code tengo la validación de que no sea vacía, para el NIF tengo una validación customizada que mas tarde explicaré como hacer, para la edad tengo una validación de fechas y por último, una múltiple validación. Además en este ejemplo he incorporado globalización para que el mensaje de la validación esté en varios idiomas.

En el atributo StringLengthValidator hay que pasar como parámetros un mínimo, un máximo, el conjunto de reglas que sigue y el mensaje, si no tuvieramos multi-idioma bastaría con poner MessageTemplate = «Lo que sea»

Para los validadores customizados hay que crearse dos clases, una que herede de Validator<T> y otra que herede de ValidatorAttribute, en mi ejemplo NifValidator.cs y NifValidatorAttribute.cs.

Éste sería el código de la clase que hereda del validatorAttribute en mi ejemplo:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;

namespace ELValidation
{
    [AttributeUsage(AttributeTargets.All)]
    public class NifValidatorAttribute : ValidatorAttribute

    {
        public NifValidatorAttribute()
        {
        }

        protected override Validator DoCreateValidator(Type targetType)
        {
            return new NifValidator();
        }
    }
}

Y el código de la clase donde se hacen las validaciones:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Validation.Configuration;
using System.Collections.Specialized;

namespace ELValidation
{
    [ConfigurationElementType(typeof(CustomValidatorData))]
    public class NifValidator : Validator<string>
    {

        public NifValidator() : base(null, null)
        {
        }

        public NifValidator(string nif, string messageTemplate)
            : this(nif, messageTemplate, null)
        {
        }

        public NifValidator(string nif, string messageTemplate, string tag)
            : base(messageTemplate, tag)
        {
        }

        protected override void DoValidate(string objectToValidate, object currentTarget, string key, Microsoft.Practices.EnterpriseLibrary.Validation.ValidationResults validationResults)
        {
            if (objectToValidate.Length > 1)
            {
                if (!ValidateNIF(objectToValidate.ToUpper()))
                {
                    string message = string.Format(this.MessageTemplate, objectToValidate);
                    this.LogValidationResult(validationResults, message, currentTarget, key);
                }
            }
            else
            {
                string message = string.Format(this.MessageTemplate, objectToValidate);
                this.LogValidationResult(validationResults, message, currentTarget, key);
            }
        }

        protected override string DefaultMessageTemplate
        {
            get { return «El NIF no es válido»; }
        }

        private bool ValidateNIF(string vNif)
        {
            string aux = string.Empty;
            int result;
            aux = vNif.Substring(0, vNif.Length – 1);

            if (aux.Length >= 7 && int.TryParse(aux, out result))
            {
                aux += letra_nif(Convert.ToUInt32(aux));
            }
            else
            {
                return false;
            }

            if (vNif == aux)
            {
                return true;
            }

            return false;

        }

        public string letra_nif(UInt32 dni)
        {
            string s_letra = «TRWAGMYFPDXBNJZSQVHLCKE»;
            dni = dni % 23;
            s_letra = s_letra[Convert.ToInt16(dni)].ToString();
            return s_letra;
        }
    }
}

Ahora podemos crear un formulario para aplicar la validación:

1

Tenemos que agregar un errorProvider y un ValidationProvider, éste último no se encuentra en la barra de herramientas por defecto, yo me he creado una nueva pestaña y lo he agregado

2

3

En las propiedades del ValidationProvider debemos asociarle el errorProvider, decirle que conjunto de reglas debe seguir en la propiedad RuleSetName, en mi caso RuleSet1 y muy importante la propiedad SourceTypeName que será el NameSpace.Clase, NameSpace, en mi caso «ELValidation.Employee, ELValidation».

Luego en cada textbox nos aparece en sus propiedades una nueva categoria que es Validation donde encontraremos 3 propiedades por cada ValidationProvider que tengamos en el formulario. En mi caso tengo PerformValidation on vpEmployee = true, SourcePropertyName on vpEmployee = Code (nombre de la propiedad de la clase Employee que asocio al textbox y que quiero validar) y por último ValidatedProperty on vpEmployee = Text (aquí ira la propiedad del textbox que queremos validar, en este caso text, si fuera un datetimepicker sería value).

Y por último, en el evento Load del formulario podemos definir un objeto de tipo empleado, cuyas propiedades se recojan de los textbox del formulario. Y mediante un botón validarlo, de tal manera que la propiedad del ValidationProvider sea true y luego llamar a ValidateChildren del formulario.

Para que sea multi-idioma el mensaje que muestra el errorprovider basta con crearse los ficheros de recursos oportunos y luego asociarlo a los atributos de las propiedades que queremos validar con MessageTemplateResourceName = «InvalidBirthMessage», MessageTemplateResourceType = typeof(Resource1), en este caso le estaríamos indicando que el mensaje de validación está en el recurso llamado Resource1 y que hace referencia a InvalidBirthMessage.

Otra cosa importante que he visto, es que cuando tenemos una clase que hereda de otra que tiene validación, las propiedades que no se sobreescriben siguen teniendo la validación del padre, sin embargo las que se sobreescriben la pierden. En el ejemplo que he hecho lo podréis comprobar en la clase Boss que hereda de Employee.

Espero que os haya ayudado este artículo.

Saludos.

 

Componentes para instalación de una aplicacion con Crystal Reports 2008

Hola a tod@s,


Al migrar los informes de una aplicación a CR2008 me he encontrado con que al hacer el instalador e intentar añadir los módulos de combinación correspondientes no los tenía lo que no me ocurría en versiones anteriores con lo que investigando me he encontrado con que te los tienes que bajar de la página de business objects.


Os dejo el enlace:


http://support.businessobjects.com/downloads/runtime.asp


Un saludo.

Sandcastle y los Tags XML para los comentarios en código.

Hola a tod@s,


 El siguiente artículo ya lo publiqué hace bastante tiempo en mi antiguo blog.


En el siguiente artículo os voy a explicar como agregar comentarios de forma sencilla con Visual Studio 2005 y luego con la herramienta Sandcastle generar una documentación en formato htm o chm. La finalidad es que si nos acostumbramos a que cada vez que hagamos una clase le añadamos comentarios siguiendo las reglas de los tags XML, podamos generar mas tarde una documentación completamente actualizada y de manera bastante rápida de nuestro proyecto. Y en caso de que usemos un generador de código, todavía es mas sencillo hacerlo.

Si estamos haciendo un proyecto en C# 2005 cuando queremos incorporar un comentario sabemos que se tiene que hacer con «//» pero si añadimos una barra mas nos aparecerá un menú contextual con etiquetas xml que tienen una característica especial:

/// <summary>
/// Esta clase hace una importante función. 
/// </summary>
public class MiClase{}

Los distintos tags que hay por ahora son:

<c> <code> <example> <exception> <include> <list>
<para> <param> <paramref> <permission> <remarks> <returns>
<see> <seealso> <summary> <typeparam> <typeparamref> <value>

Lo que voy a hacer ahora es poneros un ejemplo de como usar estas etiquetas en una clase. He construido una clase con 2 constructores, 5 propiedades y 4 métodos. No he usado todas las etiquetas, pero creo que con este ejemplo os bastará para coger conocimientos sobre el tema y si queréis profundizar siempre podréis seguir la MSDN.

Para poder llevar a cabo este ejemplo he tenido que instalarme la herramienta Sandcastle y luego usar un programa que facilita la tarea SandcastleGUI, he optado por este programa debido a su sencillez y porque es gratuito, para obtenerlo solo hay que registrarse.

Para mas información sobre como usar Sandcastle, herramientas que lo usan, etc. visitad este enlace: http://www.sandcastledocs.com/Wiki%20Pages/Home.aspx

Nota: Otra herramienta que está muy bien es la que podéis encontrar en http://www.codeplex.com/SHFB, lo único que es algo mas compleja que la que yo he usado en este ejemplo y no he encontrado la opción para poder incluir un logo. Lo bueno es que te deja parametrizar mas e incluso tiene una opción para que algunos textos aparezcan en español (pero esta opción no está muy lograda).

Mi clase con los comentarios añadidos me ha quedado así:

using System;
using System.Collections.Generic;
using System.Text;

namespace comentarios
{
    /// <summary>
    /// Clase de ejemplo
    /// </summary>
    /// <remarks>
    /// <para>Con esta clase aprenderemos los pasos básicos para <br/>
    /// crear una buena documentación con Sandcastle.</para>
    /// <img src=»Class1.png» mce_src=»Class1.png»></img>
    ///</remarks>
    public class Class1
    {
        /// <summary>
        /// Constructor principal de la clase.
        /// </summary>
        /// <remarks>
        /// <para>El constructor principal no admite parámetros.</para>
        /// </remarks>
        /// <seealso cref=»Class1(String, String, Boolean, Int32, DateTime)»/>
        public Class1()
        {
        }

        /// <summary>
        /// Sobrecarga del Constructor en el que se inicializan las propiedades.
        /// </summary>
        /// <example>
        /// <code>
        /// Class1 miClase = new Class1(«uno», «dos», 3, true, DateTime.Today);
        /// string p1 = miClase.Propiedad1;
        /// string p2= miClase.Propiedad2;       
        /// </code>
        /// </example>
        /// <remarks>
        /// Este segundo constructor necesita 5 parámetros, los dos primeros de tipo cadena <br/>
        /// el tercero de tipo booleano, el cuarto de tipo entero y el quinto de tipo fecha.
        /// </remarks>
        /// <param name=»prop1″>Propiedad 1 de tipo cadena</param>
        /// <param name=»prop2″>Propiedad 2 de tipo cadena</param>
        /// <param name=»prop3″>Propiedad 3 de tipo booleano</param>
        /// <param name=»prop4″>Propiedad 4 de tipo entero</param>
        /// <param name=»prop5″>Propiedad 5 de tipo fecha</param>
        /// <seealso cref=»Class1()»/>
        public Class1(string prop1, string prop2, bool prop3, Int32 prop4, DateTime prop5)
        {
            _sPropiedad1 = prop1;
            _sPropiedad2 = prop2;
            _bPropiedad3 = prop3;
            _iPropiedad4 = prop4;
            _dPropiedad5 = prop5;
        }

        /// <summary>
        /// Campo privado de tipo cadena, propiedad 1.
        /// </summary>
        private string _sPropiedad1 = string.Empty;
        /// <summary>
        /// Campo privado de tipo cadena, propiedad 2.
        /// </summary>
        private string _sPropiedad2 = string.Empty;
        /// <summary>
        /// Campo privado de tipo booleano, propiedad 3.
        /// </summary>
        private bool _bPropiedad3 = false;
        /// <summary>
        /// Campo privado de tipo entero, propiedad 4.
        /// </summary>
        private Int32 _iPropiedad4 = 0;
        /// <summary>
        /// Campo privado de tipo fecha, propiedad 5.
        /// </summary>
        private DateTime _dPropiedad5 = DateTime.MinValue;

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_sPropiedad1</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_sPropiedad1</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _sPropiedad1.</value>
        /// <seealso cref=»_sPropiedad1″/>
        public string Propiedad1
        {
            get {
                return _sPropiedad1;
            }
            set{
                _sPropiedad1 = value;
            }
        }

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_sPropiedad2</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_sPropiedad2</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _sPropiedad2.</value>
        /// <seealso cref=»_sPropiedad2″/>
        public string Propiedad2
        {
            get {
                return _sPropiedad2;
            }
            set {
                _sPropiedad2 = value;
            }
        }

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_bPropiedad3</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_bPropiedad3</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _bPropiedad3.</value>
        /// <seealso cref=»_bPropiedad3″/>
        public bool Propiedad3
        {
            get {
                return _bPropiedad3;
            }
            set
            {
                _bPropiedad3 = value;
            }
        }

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_iPropiedad4</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_iPropiedad4</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _iPropiedad4.</value>
        /// <seealso cref=»_iPropiedad4″/>
        public Int32 Propiedad4
        {
            get { return _iPropiedad4; }
            set { _iPropiedad4 = value; }
        }

        /// <summary>
        /// Propiedad pública que obtiene o establece el valor de <c>_dPropiedad5</c>.
        /// </summary>
        /// <remarks>Propiedad pública que obtiene o establece el valor de <c>_dPropiedad5</c></remarks>
        /// <value>Obtiene o establece el valor del miembro _dPropiedad5.</value>
        /// <seealso cref=»_dPropiedad5″/>
        public DateTime Propiedad5
        {
            get { return _dPropiedad5; }
            set { _dPropiedad5 = value; }
        }

        /// <summary>
        /// Método público que devuelve un booleano al comparar la longitud <br/>
        /// de los miembros  _sPropiedad1 y _sPropiedad2
        /// </summary>
        /// <returns>Devuelve un booleano</returns>
        public bool Metodo1()
        {
            return (_sPropiedad1.Length < _sPropiedad2.Length);
        }

        /// <summary>
        /// Método privado que establece el valor del miembro _iPropiedad4 <br/>
        /// a la suma de los 2 parámetros pasados.
        /// </summary>
        /// <param name=»x»>Primer parámetro entero</param>
        /// <param name=»y»>Segundo parámetro entero</param>
        private void Metodo2(Int32 x, Int32 y)
        {
            _iPropiedad4 = x + y;
        }

        /// <summary>
        /// Método público que llama al método privado Metodo2.
        /// </summary>
        /// <param name=»x»>Primer parámetro entero</param>
        /// <param name=»y»>Segundo parámetro entero</param>
        public void Metodo3(Int32 x, Int32 y)
        {
            Metodo2(x, y);           
        }

        /// <summary>
        /// Método públic que devuelve un valor doble obtenido <br/>
        /// a través de la división de dos enteros pasados como parametros.
        /// </summary>
        /// <param name=»x»>Primer parámetro entero</param>
        /// <param name=»y»>Segundo parámetro entero.</param>
        /// <returns>Devuelve un doble a partir de división de enteros.</returns>
        /// <exception cref=»System.Exception»>Se produce una excepción cuando intentamos dividir por cero.</exception>
        public Double Metodo4(Int32 x, Int32 y)
        {
            try
            {
                return x / y;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
    }
}

Una vez que tenemos el proyecto con los comentarios pertinentes tenemos que habilitar la opción de que al compilar se cree el fichero XML con los comentarios.

Nota: Es muy importante tener en cuenta que si nuestro proyecto hace referencia a otros assemblies, para que se genere correctamente, dichos assemblies tienen que tener asociado su XML de documentación correspondiente, en caso contrario no garantizo que la documentación creada esté correcta.

art9_01

Generamos la solución y ya podemos utilizar el Sandcastle a través del programa SandcastleGUI para generarnos nuestra documentación.

art9_02

Como podemos observar en la figura anterior vamos rellenando la información requerida sobre nuestro proyecto.

En la zona «General» rellenamos la primera casilla con la ruta donde se encuentra/n nuestra/s assembly/is, en la segunda casilla le decimos donde queremos que nos deje la documentación generada, la tercera casilla es para que en caso de que añadamos archivos adjuntos como imágenes las pueda encontrar, en mi caso he incluido la imagen del diagrama de la clase que he creado, en la cuarta casilla le indicamos el/los namespace/s que queremos documentar.
En la zona «Custom» indicamos el nombre del programa, la linea de copyright y en caso de que queramos un logo su ruta.
En la zona «Compilation» le indicamos si sigue una sintaxis de C#, VB o C++ manegado, si queremos que los ficheros generados (cuando es un Website) tengan nombres «amigables» o no (es decir, que los nombres de los htm generados tengan algún significado como F_comentarios_Class1__bPropiedad3.htm o que sea un nombre como si estuviera encriptado), si queremos que nos muestre las propiedades, métodos, etc privados (Document internals), que nos formatee a la sintaxis de C# los ejemplos, si queremos tener enlaces a la MSDN para las clases usadas del framework, y por último en qué formato lo queremos, para el ejemplo que he creado quiero un Website con plantilla Hana y que me cree el árbol de contenidos a la izquierda.
El motivo de que haya querido un Website es que te da la posibilidad de tener un buscador.

Una vez que hayamos puesto todas las opciones con las que queremos que se genere nuestra documentación pulsamos el botón «Start documenting» y eso hace que nos aparezca una ventana de lineas de comando haciendo un montón de cosas.

art9_03

Cuando se cierra la ventana de lineas de comando ya tenemos generada nuestra documentación, para la opción Website, abrimos con un navegador el archivo index.htm (que es el principal).

art9_04

Si navegamos a través de los constructores, métodos y propiedades que hemos comentado veremos como se ha formateado las líneas de comentario escritas en el proyecto en esta estupenda documentación. Por ejemplo, aunque no se vea muy bien, gracias a lo que hemos escrito en las etiquetas <sumary> se puede ver reflejado en la descripción de los miembros de la clase:

art9_05

También podemos usar etiquetas típicas de HTML (pero tratando de hacerlo como si de XML se tratara, por ejemplo la etiqueta <BR> no tiene / final, pero aquí se debe poner quedando <BR/>), e incluso podemos insertar imágenes como se puede apreciar en el siguiente dibujo (ver el código de la clase, los comentarios creados en la declaración de la clase Class1):

art9_06

Podemos aumentar la calidad de nuestra documentación añadiendo ejemplos prácticos (con las etiquetas <example> y <code>) y que al generarse se nos permite copiar el código como vemos en la siguiente imagen (ver el código de la clase, los comentarios creados en la declaración del segundo constructor):

art9_07

También se puede mostrar las excepciones que se pueden producir en un método. (ver el código de la clase, los comentarios creados en el método 4).

art9_09

Como os había comentado, tenemos un buscador que al poner palabras para buscar, en caso de que las encuentre nos indica donde y nos las marca en amarillo:

art9_08

Para que os quede mas claro, podéis crearos un proyecto, usar la clase que he definido y generar la documentación como os he ensañado, de esta forma podréis navegar por la documentación y ver el por qué de los comentarios que he usado.

Espero que os haya parecido interesante.