lunes, 10 de octubre de 2011

Le blog de Thibaud :-): Footer on WPF DataGrid: by use several synchronized datagrid

It's a great idea and just what I need. Would be great to have synchronized the row sizing too. Anyway a good starting point for me. Thanks again.

miércoles, 13 de enero de 2010

Cuando y como implementar IDisposable

Cuando implementar la interfaz IDisposable:

  1. Cuando la clase contenga alguna variable de tipo "Unmanaged".
  2. Cuando la clase contenga alguna variable que implemente la interfaz IDisposable.
  3. Cuando la clase contenga manejadores (handlers) de eventos.
En los dos primeros casos el motivo es obvio, pero en el tercero es un poco más obscuro. Cuando tengamos una clase que contenga manejadores de eventos hay que implementar la interfaz IDisposable para quitar el manejador cuando se llame al método Dispose. Si no se hace las referencias entre las dos clases se mantienen en memoria y no se eliminan.

Como implementar la interfaz IDisposable:

Para una correcta implementación de la interfaz se deberá usar el siguiente código obviando el generado automáticamente por VS puesto que este no permite efectuar correctamente un Override del método Dispose en las clases herederas al no poder consultar el estado de disposedValue.


#Region "IDisposable"
    Private m_disposed As Boolean 

    Protected ReadOnly Property Disposed() as Boolean
        Get
            Return m_disposed
        End Get
    End Property

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not m_disposed Then
            If disposing Then
                ' Free other state (managed objects).
            End If
            ' Free your own state (unmanaged objects).
            ' Set large fields to null.
        End If

        m_disposed = True
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub

    Protected Overrides Sub Finalize()
        ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        Dispose(False)
        MyBase.Finalize()
    End Sub
#End Region

viernes, 8 de enero de 2010

Declaración de regiones en el código

Toda clase deberá estar incluir estas regiones para permitir ocultar las partes que no interesen en un momento dado del desarrollo.

  1. Attributes: dentro de esta región estarán todos los atributos (variables) de la clase, tanto estaticos como de instancia.
  2. [Constants]: se incluirán aquí tanto las Const como los atributos ReadOnly.
  3. Properties: contendrá las propiedades si existen.
  4. [Events]: contendrá las declaraciones de los eventos de la clase.
  5. Public Methods: contendrá todos los métodos excepto los declarados Private y los manejadores de eventos.
  6. [Event Handlers]: se incluirán aquí todos los métodos manejadores de eventos que defina la clase si los hay.
  7. Private Methods: incluirá todos los metodos privados de la clase.
  8. [Interface implementations]: opcionalmente se podrán crear regiones para las implementaciones de las interfaces (sobre todo cuando sean interfaces accesorias como IDisposable, ICloneable, etc).
Las regiones aparecerán en este orden dentro de la clase. Las marcadas entre corchetes son opcionales y solo aparecerán en el caso de que haya elementos de ese tipo.

jueves, 7 de enero de 2010

Declaración de variables en métodos

Todas las variables locales de los métodos se declararán al inicio del método antes de cualquier código y no incluirán su inicialización. Inicializar se considera parte del código del método.

Excepciones permitidas:

  • Constructores que deben llamar a otros constructores: como la primera instrucción debe ser la llamada al constructor anterior se permite romper la norma.
  • Instrucciones ForEach xxx As xxx In xxx o For xxx As xxx To xxx: como la propia declaración de la instrucción incluye una sintaxis para la declaración de variables se admite su uso puesto que resulta simple observar en el código cual es la variable principal del bucle.
  • Instrucción Using: como la propia instrucción obliga a que la declaración de la variable se haga dentro del bloque se permite romper la norma.

Con esta norma se propone separar la declaración de elementos y su uso, de manera que no sea necesario buscar en el código cuando una variable determinada fue declarada, puesto que todas están declaradas al inicio del método.

miércoles, 6 de enero de 2010

Truco: Como usar cualquier clase en un Setting

Los Settings son una manera extremadamente rápida y sencilla de incluir parámetros que puedan ser configurados por el usuario (además de incluir constantes si son Settings de aplicación).

El problema viene cuando uno quiere guardar un objeto propio en los Settings. Después de todo es mucho mas sencillo guardar en un Setting un objeto de una clase nuestra que tener que descomponer dicha clase en sus atributos más relevantes y guardar estos en los Setting.

Inicialmente uno cree que pude salir adelante con la opción Browse:


Opción de Browse en los Settings


Enseguida nos daremos cuenta de que solo funciona con algunos tipos incluidos en el Framework y con ciertos tipos declarados en otros Assemblies diferentes al actual con lo que no podremos incluir ningún tipo declarado en el proyecto que estemos desarrollando (un ejecutable presumiblemente puesto que le estamos añadiendo Settings).

Pues bien, existe una manera de añadir los tipos deseados retocando un poco lo que el Visual Studio genera (está probado con VS2005 y VS2008). Los pasos a seguir son los siguientes:

  • Crearemos una propiedad con el nombre que deseemos y le dejaremos el tipo que sale por defecto.
  • Seleccionaremos la opción de ver todos los ficheros del proyecto en el Solution Explorer

  • Abriremos el fichero Settings.Designer.vb que se encuentra dentro de My Project -> Settings.settings (si es un proyecto WPF no se puede abrir así y hay que abrir directamente el fichero Settings.Designer.vb almacenado en disco).
  • Buscaremos la propiedad que creamos en el primer paso y le pondremos el tipo deseado.
  • Por ultimo abriremos el fichero Settings.settings seleccionando Open With del menú contextual y escogiendo el editor XML y buscaremos la propiedad creada y le cambiaremos el Type por el nombre  completo de nuestro tipo (Namespace.Class) también conocido como Full Qualified Name.

martes, 5 de enero de 2010

Utilización de sintaxis .

Cuando se codifique se explicitará siempre el origen de los métodos a ejecutar con el formato <ObjetoOClase>.<MetodoOPropiedad>, sea el objeto una variable o parámetro (en cuyo caso hay que explicitarlo obligado por el compilador), sea este una referencia a Me, a MyBase, a el nombre de la clase si es un método estático o a cualquier otro tipo de elemento origen de métodos.

Esto es especialmente útil cuando se hereda de una clase pues permite ver muy rápidamente cuando se usan métodos de la clase base o de la clase implementada.

Con el fin de mantener constante la sintaxis <ObjetoOClase>.<MetodoOPropiedad> tampoco se usarán las propiedades predeterminadas ni se accederán las colecciones como si fueran matrices usando indices, en su lugar se llamará a la propiedad Item(index).

El seguir una estructura fija facilita leer el código al no tener que pensar si el método XXX() está definido como método estático, como método propio o como método definido en alguna clase heredada. De la misma manera al no acceder a las colecciones como a las matrices se evita que se confundan unas con otras.

lunes, 4 de enero de 2010

Estructura de las funciones

Para estructurar correctamente el código las funciones tendrán únicamente un punto de retorno al final de la función. De esta manera es más fácil seguir la estructura del código puesto que no hay retornos funcionando como "goto" ocultos.

La variable devuelta en el retorno de la función se llamará siempre result (excepto en los casos en que el resultado se pueda calcular en una sola linea en cuyo caso no será necesario declarar dicha variable).

Por lo tanto la estructura de una función siempre quedará inicialmente así:




He creado un Snippet (con la herramienta SnippetEditor) para crear el esqueleto automáticamente con el siguiente código:

<?xml version="1.0" encoding="utf-8"?>

<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>Create Function</Title>
      <Author>Ignacio Soler (Sipro Ingenieria)</Author>
      <Description>Create Function</Description>
      <HelpUrl></HelpUrl>
      <SnippetTypes />
      <Keywords />
      <Shortcut>creaFunc</Shortcut>
    </Header>
    <Snippet>
      <References />
      <Imports />
      <Declarations>
        <Literal Editable="true" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
          <ID>FunctionName</ID>
          <Type />
          <ToolTip />
          <Default>FunctionName</Default>
          <Function />
        </Literal>
        <Literal Editable="true" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
          <ID>ReturnType</ID>
          <Type />
          <ToolTip />
          <Default>ReturnType</Default>
          <Function />
        </Literal>
      </Declarations>
      <Code Language="VB" Kind="method decl" Delimiter="$"><![CDATA[    Public Function $FunctionName$() As $ReturnType$
        Dim result As $ReturnType$

        Return result
    End Function]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>