martes, 27 de noviembre de 2012

Encapsulando Silverlight en controles ASP.NET

 

En respuesta a esta inquietud sobre Custom Controls que me plantea uno de los seguidores del Blog, German:

“si un CustomControl, es una dll con propiedades, métodos y eventos propios. Se puede consumir esa dll desde un proyecto web común?. O sea que aparezca el control (CustomControl) en la barra de herramientas para poder arrastrarla y soltarla en algún lugar de la aspx.”

Realizo esta nueva entrada al blog.

En primer lugar y como respuesta a la inquietud planteada debo decir, que efectivamente, aunque un CustomControl es una DLL con métodos y eventos propios, los custom controls de Silverligth solo se pueden colocar dentro de la barra de herramientas y arrastrar y soltar pero en páginas XAML de Silverlight, a páginas ASPX comunes no. Estos no son reconocidos como Custom Controls para ASP.NET.

Busqué por allí,porque recuerden que tampoco me las se todas, y encontré que es posible encapsular funcionalidad Silverligth en custom controls de ASP.NET, de esta forma es posible colocar en la barra de herramientas un control de ASP.NET, arrastrarlo y soltarlo en una página ASPX común y tener allí funcionalidad Silverlight. Sin embargo, la mala noticia es que la funcionalidad Silverlight a la que podemos acceder de esta forma es muy limitada, por las pruebas que realicé solo se pueden utilizar controles XAML muy básicos (que no tengan Code-Behind ni un amplio rango de animaciones; tampoco pueden tener Custom Controls ni interaccionar con Multimedia, etc.). Sin embargo, aún con controles básicos de Silverlight, se logra extender y, en mucho, la funcionalidad de nuestras páginas ASP.NET comunes.

Si deseas saber más te recomiendo que visites:

http://msdn.microsoft.com/en-us/magazine/cc135987.aspx

También como dice allí, es posible interaccionar con Silverlight a través de los controles asp:Xaml y asp:Media que son controles ASP.NET AJAX introducidos en la liberación ASP.NET Futures de mayo de 2007.

Sin embargo, esta posibilidad no la exploré, pues se salé del rango de acción de lo esperado en la pregunta de Germán.

No obstante si deseas explorar esta posibilidad te dejo el Link desde donde se pueden bajar e instalar estos controles:

http://www.microsoft.com/en-us/download/details.aspx?id=22457

Más detalle en el video.

Espero que les guste.


domingo, 23 de septiembre de 2012

Aprendiendo Biztalk Lab1

 

A continuación, un video de enseñanza que se centra en la explicación de cómo se realizó el primer laboratorio del Training Kit de Biztalk Server 2010.

Espero que les guste.

Instrucciones para la instalación de los laboratorios del Training Kit de Biztalk

 

Para que puedas ejecutar, sin problemas, los laboratorios de Biztalk del Training Kit:

http://www.microsoft.com/en-us/download/details.aspx?id=17956

Debe seguir estas instrucciones:

1. Descomprimirlos en la Raiz del C:. Que quede la estructura de directorios así:

C:\BizTalk2010Labs\Labs…

2. Habilitar el IIS con la consola del II6 instalada.

3. Asegurarse que el host de Bistalk Server application tenga configurado no realizar una Trusted Autentication. Es decir, que no esté chequeada esta opción.

clip_image002

4. Instalar el WCF LOB (Line Of Bussiness) Adapter. Este se puede descargar de este enlace:

http://www.microsoft.com/en-us/download/details.aspx?id=10903

Este proporciona un modelo de programación simplificado en la parte superior del modelo de canal de WCF mediante la adición de navegación de metadatos, búsqueda y recuperación de la funcionalidad y herramientas de desarrollo para generar y probar el adaptador código.

Asegurarse que la instalación sea completa:

clip_image003

5. Instalar el paquete de adaptadores de Biztalk (Biztalk Adapter Pack) de forma completa.

El BizTalk Adapter Pack proporciona conectividad con SAP, Oracle E-Business Suite, Siebel y Oracle SQL y bases de datos. El BizTalk Adapter Pack se puede instalar junto con, o separadamente, BizTalk Server. Se incluyen tanto en las ediciones Enterprise y Standard de BizTalk.

Afortunamente, viene con la Development Edition:

clip_image004

Luego, se procede con su instalación.

Aquí, se nota que el WCF LOB (Line Of Bussiness) Adapter, venia también en la versión development de Biztalk:

clip_image006

Simplemente, se reconoce como ya instalado dicho adaptador. En este punto, se procederá a instalar todos los adaptadores, que aparecen en la pantalla, como faltantes por instalación y siempre se efectuará la instalación completa:

clip_image007

Al final, se comprueba que todos los adaptadores, se instalaron apropiadamente.

clip_image009

Y se finaliza la instalación.

6. Restaurar las bases de datos AdventureWorks y TailspinToys de las rutas:

C:\BizTalk2010Labs\Labs\Data\AdvWorks.bak y

C:\BizTalk2010Labs\Labs\Data\TailspinToys.bak

Respectivamente.

Usando el Management Studio de Sql Server.

clip_image011

7. Verificar que todas las cuentas de Biztalk Service tengan el rol de db_owner, para las bases de datos restauradas.

clip_image013

clip_image015

8. Verificar que la cuenta EveryOne o Todos tenga acceso completo a la ruta C:\BizTalk2010Labs.

clip_image016

lunes, 10 de septiembre de 2012

Instalación de Biztalk Server 2010 Developer Edition

El propósito de este artículo es explicar lo que hice para lograr la instalación de Biztalk Server 2010 Developer Edition en mi máquina, para de esta forma, ayudar a otros en sus procesos de instalación.

Lo primero es instalar los prerrequisitos de Software, que se muestran en la página de descarga de Biztalk server Developer Edition.

http://www.microsoft.com/en-us/download/details.aspx?id=24433

· SQL Server 2008 R2 or SQL Server 2008 SP1

Debido a que se poseen pocos ingresos económicos, se instala:

SQL Server 2008 R2 express edition. Que es gratis. De esta dirección:

http://www.microsoft.com/en-us/download/details.aspx?id=23650

La versión de 64 Bits

· SQL Server 2005 Notification Service

Como dice la guía de instalación de Biztalk Server 2010:

Haga clic en el Feature Pack de Microsoft SQL Server 2005 - diciembre de 2008 (

http://www.microsoft.com/en-us/download/details.aspx?id=11988

) o desplácese hasta él.

Según la plataforma, descargue el paquete adecuado de los tres componentes siguientes:

Cliente nativo de Microsoft SQL Server

· Paquete X86 (sqlncli.msi)

· Paquete X64 (sqlncli_x64.msi)

Colección de objetos de administración de Microsoft SQL Server 2005

· Paquete X86 (SQLServer2005_XMO.msi)

· Paquete X64 (SQLServer2005_XMO_x64.msi)

Componentes de cliente de Microsoft SQL Server 2005 Notification Services

· Paquete X86 (SQLServer2005_NS.msi)

· Paquete X64 (SQLServer2005_NS_x64.msi)

Se descargaron e instalaron los componentes, para la versión de 64 bits.

· Internet Information Services (IIS) Version 7.5 and 7.0

Simplemente, se activó esta característica en el sistema operativo.

· Microsoft Office Excel 2010 or 2007

Ya se tenía instalado en el equipo.

· SQLXML 4.0 with Service Pack 1.

Esto se pudo descargar desde este enlace e instalar gratis:

http://www.microsoft.com/en-us/download/details.aspx?id=30403

Se descargó e instaló la versión de 64 Bits.

· Microsoft Visual Studio 2010

Se instaló la versión ultimate y el service pack 1.0, para 64 bits.

· Microsoft .NET Framework 4 and .NET Framework 3.5 with Service Pack 1 (SP1)

Se instala al instalar Visual Studio 2010.

La instalación se realiza en un Windows 7.0 Home Premium Service Pack 1.0

Lo primero ejecutar el archivo comprimido BT2010DEV_EN.exe, el cual se obtiene de la ruta:

http://www.microsoft.com/en-us/download/details.aspx?id=24433

Al hacerlo, el contenido de este comprimido queda en la ruta que le indiquemos:

clip_image002

Vamos a la ruta, donde queda el contenido del comprimido, y ejecutamos el Setup.exe.

clip_image003

Lo primero que se hace es cliquear el enlace, para ver la guía de la instalación, lo cual carga el enlace:

http://www.microsoft.com/es-es/download/details.aspx?id=11503

De allí se descarga la guía para la instalación en Windows 7.

En la guía se indican los pasos de instalación del Software requerido, como se ha hecho hasta el momento y además lo siguiente:

· Deshabilite el protocolo de memoria compartida

Esto como se pudo consultar, se trata de configurar en SQL Server esta característica, que por defecto, tras la instalación, se encuentra habilitada.

clip_image005

Simplemente, se configura, para que no esté habilitada.

La idea es que los clientes que tienen habilitada la opción Shared Memory solo se pueden conectar a la instancia de SQL server que corre en el mismo equipo, lo cual no es usable para la mayoría de las actividades de base de datos.

Los clientes que usan MDAC 2.8 o anterior, no pueden usar el protocolo de memoria compartida.

Hay que reiniciar los servicios de SQL Server, para que el cambio sea tenido en cuenta.

clip_image007

Simplemente, se detiene y vuelve y se inicia.

Sin embargo, al hacer esto, se presenta un error. El servicio no puede iniciar, si no se habilita la opción Shared Memory. Quizás sea un prerrequisito de la edición express de la base de datos SQL Server 2008 R2, el tener la memoria compartida habilitada.

Debido a este problema, se vuelve y se habilita l memoria compartida; igual, en esta instalación, casera, la instancia de SQL Server está en la misma máquina.

· Únase al grupo de administradores local. Al ser un equipo propio, mi cuenta pertenece al grupo de administradores.

· Configure el registro de eventos de la aplicación. *Solo es necesario si usa el servicio web del adaptador de Windows SharePoint Services. . Esto no me aplica.

Una vez se tienen en cuenta estas consideraciones, se inicia con la instalación de BizTalk:

clip_image008

Y sale la primera pantalla del Wizard:

clip_image009

Le doy continuar y acepto las condiciones de la licencia, en la próxima pantalla:

clip_image010

En lo personal, prefiero no participar en el programa de experiencia de usuario de Biztalk:

clip_image011

A continuación, es momento de elegir las componentes que deseamos instalar de Biztalk y como se trata de una instalación, para probar, si se puede, todo lo referente a Biztalk y como, además se posee espacio en disco suficiente, se elige la instalación de todas las componentes; incluso del Software adicional. Una explicación detallada de cada componente, se encuentra en la guía de instalación.

clip_image012

Pese a que se instaló el software, que se indicó, para la instalación de Biztalk, debido a la elección de componentes, que elegí, para la instalación, el Wizard se dio cuenta, que requería la instalación de componentes adicionales y me da varias opciones, para obtenerlos. Se elige la opción de obtenerlos desde Internet:

clip_image013

Ahora, viene la pantalla resumen, con los componentes que se instalarán:

clip_image014

Y se presiona el botón, para instalar:

clip_image015

Luego de este proceso, donde en mi caso, tomo la mayoría del tiempo, en la bajada desde internet de las componentes adicionales requeridas; se muestra la pantalla de éxito, en la instalación de Biztalk server 2010.

clip_image016

Le doy Finish, para entrar a la consola de configuración de Biztalk:

clip_image018

Como la base de datos está en el mismo equipo, elijó la configuración básica, ingresando el usuario y la clave para la base de datos y doy click en el botón para Configurar.

Como dice en la guía de instalación, sale un mensaje de advertencia, de seguridad, cuando la cuenta que se usa coincide, con la cuenta administradora del equipo, acá aceptamos el riesgo de seguridad.

clip_image019

Es decir, elegimos la opción Sí.

Y sale un error en la configuración del portal BAM:

clip_image020

Se busca en internet la causa y de acuerdo a este foro:

http://social.msdn.microsoft.com/Forums/en-US/biztalkgeneral/thread/c99e608b-2c29-4ef1-889c-432c7117f247/

El IIS 7, prerrequisito para la instalación, requiere tener los componentes de compatibilidad con IIS 6, para que el portal BAM, se pueda configurar sin problemas.

En este link, se explica lo que hay que hacer, para instalar estos componentes de compatibilidad:

http://technet.microsoft.com/es-es/library/bb397374(v=exchg.80).aspx

Se siguió la guía para Windows 7.

Es decir:

1. Haga clic en Inicio, en Panel de control, Programas y características y, a continuación, haga clic en Activar o desactivar características de Windows.

2. Abra Internet Information Services.

3. Abra Herramientas de administración web.

4. Abra Compatibilidad con la administración de IIS 6.0.

5. Active las casillas para Compatibilidad con la configuración de IIS 6 y metabase de IIS 6 y Consola de administración de IIS 6.

6. Haga clic en Aceptar.

clip_image021

clip_image022

Ahora, se intenta de nuevo, realizar la configuración y ahora sí, no sale problema, con la configuración, para el portal BAM:

clip_image023

Por tanto, se da continuar en dicha pantalla.

clip_image024

Luego de esto, el resultado de la configuración, me muestra que se pudieron configurar exitosamente, algunos componentes, pero otros no y el Wizard, me da la posibilidad de realizar una configuración personalizada, para tener control de suministrar la información apropiada, para efectos de lograr una adecuada configuración de todos los componentes.

clip_image026

Aunque se realizó esta instalación, no se pudo configurar lo concerniente al BAM y esta vez se descubre que es debido al uso de SQL Server 2008 R2 Express Edition que no viene con el Analisys Services, que es requerido para las herramientas BAM.

clip_image028

Por el momento, se deja la instalación de esta forma. Cuando se consiga SQL Server 2008 la versión Enterprise que venga con Analisys Services, se configurará el BAM.

En cuanto a la configuración del EDI, se indica:

clip_image030

Sin embargo, como dice en este enlace:

http://msdn.microsoft.com/es-es/library/bb743506.aspx

Consideraciones para configurar el tiempo de ejecución de EDI y AS2 de BizTalk

Al configurar el tiempo de ejecución de EDI y AS2 de BizTalk en BizTalk Server 2010, tenga en cuenta lo siguiente:

Debe configurar el SSO empresarial, el grupo y el tiempo de ejecución de BizTalk antes de configurar el tiempo de ejecución de EDI y AS2 de BizTalk.

BAM debe configurarse antes para configurar las características de creación de informes de estado en tiempo de ejecución de AS2 y EDI/AS2.

Si solo va a configurar EDI, BAM no es necesario.

Luego, se requiere la instalación de las herramientas BAM, el problema, entonces, sigue siendo la base de datos SQL Server 2008 R2 Express Edition, que se usó para la instalación.

viernes, 7 de septiembre de 2012

Visual Studio– Solucionar problema con el editor de Transac SQL, luego de instalar SQL Server 2008, en la máquina

 

 

Este Post es para inmortalizar un hallazgo que hice, en otro foro:

http://social.msdn.microsoft.com/Forums/en/vssetup/thread/27ef7c94-4410-4925-ab22-3fec475b1885

La idea es que después de instalar SQL server 2008 en la máquina asignada a mi persona en la empresa, se presentó un error, consistente en que ya no se reconocían en VS2010, los archivos de extensión SQL y al ir a las opciones y herramientas de base de datos, no se presentaba la pantalla con la información del editor de Transac SQL, para solucionar esto, porque era muy necesario. Se siguieron estos pasos:

1. Cargar la información de archivos del DVD de instalación de Visual Studio.

2. Ir a la carpeta WCU.

3. Ir a la carpeta DAC.

4. Instalar los siguientes MSIs:

  • DACFramework_enu.msi
  • DACProjectSystemSetup_enu.msi
  • TSqlLanguageService_enu.msi

Esto me funcionó muy bien.

Se corrigió el problema sin necesidad de Reinstalar todo el Visual Studio, lo cual es muy engorroso.

sábado, 16 de junio de 2012

Solución al problema inesperado The "CreateRiaClientFilesTask" task failed unexpectedly.

 

Sí y fue muy inesperado y me dio muchos dolores de cabeza y me causó mucho estrés. Esta es la historia:

Como de costumbre, generaba y construía mi solución, para verificar las implementaciones que iba realizando. Sin ningún tipo de inconveniente. Un día, cuando el Visual Studio se hallaba en proceso de generar o construir la aplicación, de forma accidental, con el pie, desconecté el computador del enchufe de energía eléctrica, por tanto, durante el proceso de compilación, digámoslo así, se cortó el suministro de energía. Después de conectar y encender de nuevo mi computador y continuar en la tarea que iba, que era precisamente, compilar y generar la solución, para verificar unas últimas implementaciones, para mi sorpresa y desconcierto, me salía este mensaje:

Error    12    The "CreateRiaClientFilesTask" task failed unexpectedly.
System.Web.HttpException (0x80004005): Could not load file or assembly 'OpenExcel, Version=0.3.2.18934, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG)) ---> System.Configuration.ConfigurationErrorsException: Could not load file or assembly 'OpenExcel, Version=0.3.2.18934, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG)) ---> System.IO.FileLoadException: Could not load file or assembly 'OpenExcel, Version=0.3.2.18934, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG)) ---> System.IO.FileLoadException: Could not load file or assembly 'OpenExcel' or one of its dependencies. The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))

 

La DLL, por supuesto, se encontraba en su lugar, no tenía sentido el error de compilación.

Busqué en la red, por una solución y probé varias cosas:

1. Eliminar la DLL de la lista de las referenciadas y volverla a agregar, compilar de nuevo y nada. No funcionó.

2. Limpiar la solución y volver a construir y nada.

3. Reiniciar el Visual Studio y nada.

4. Reiniciar el computador y nada.

5.Eliminar los archivos temporales en C:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files y compilar de nuevo y nada.

 

Hasta que por fin!!. Lo que me funcionó fue esto:

  1. Cerrar el Visual Studio
  2. Borrar los archivos temporales en c:\Windows\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files.
  3. Reiniciar el Visual Studio
  4. Construir o compilar la solución.

Espero que les sirva tanto como a mí.

martes, 1 de mayo de 2012

Scripting en Silverlight

 

Hoy deseo escribir acerca del Scripting en Silverlight, pues esto me permitió solucionar un problema de negocio y considero apropiado hacerles partícipes, por si en algún momento lo llegan a requerir.

Bien, comencemos con el problema.

El problema o necesidad era poder ejecutar unos cálculos, con base en unas fórmulas, en una aplicación Silverlight, pero el usuario quería ser capaz de poder poder modificar dichas fórmulas a voluntad y que el aplicativo reconociera el cambio y las aplicase sin mayores traumatismos.

Comencé a buscar y lo que deseaba encontrar era una forma, para poder ejecutar el código expresado en una cadena de texto, quería encontrar un mecanismo parecido al Eval de JavaScript, pero que me funcionara en Silverlight.

Fruto de la búsqueda, surgieron varias posibilidades, todas inexploradas por mi hasta el momento y todas relacionadas con la aplicación de lenguajes dinámicos. Aquellos que usan o se construyen sobre el DLR ( Dynamic Language Runtime) de .NET  y cuyos ejemplos emblemáticos son: IronRuby o IronPython, implementaciones para .Net de los lenguajes dinámicos Ruby y Python.

En primer lugar, se exploró IronRuby y aunque, como pude comprobar con ejemplos, permitía la ejecución del código expresado en una cadena de texto. Mi problema requería otros aspectos adicionales: Ejecutar una fórmula (un texto), pero a la cual le pudiera definir el valor de los términos y de la cual pudiera obtener su resultado. Quizás, profundizando un poco más con IronRuby, hubiese podido resolver el problema. Sin embargo, como nos pasa muy a menudo, no tenía el suficiente tiempo, para hacer una exploración completa del lenguaje y, además, mi problema requería también que la sintaxis que usara fuera en C#, pues se trataba era de externalizar el trabajo con las fórmulas, es decir, ya se tenía el código y la lógica de la realización de los cálculos, donde la fórmula, por el momento se hacia sobre los términos, pero donde el usuario, si quería no la podía modificar. De haber concluido que la respuesta era IronRuby, habría tenido que traducir un código de C# a IronRuby, lo que hubiese requerido un esfuerzo adicional.

Enfocado ya en mi investigación sobre lenguajes dinámicos , descubrí Script.NET Language. Lo primero que noté, es que podía trabajar con la Sintaxis de C# y que al igual que con IronRuby podía ejecutar el código expresando en una cadena de texto. Incluso pude notar que era más fácil su utilización, comparada con IronRuby, en donde, todo se basa en referenciar en el proyecto de Silverlight un único assembly e interactuar con unos objetos y métodos casi intuitivos.

La página de donde lo puedes descargar si te interesa es esta:

http://www.protsyk.com/scriptdotnet/wiki/index.php?title=Main_Page

Bien, lo descargas y de la ruta de tu disco duro donde queda instalado (en mi caso):

C:\Program Files\Petro Protsyk\S#\Silverlight 4

Tomas la dll: Scripting.SSharp.Silverlight.dll

Y la llevas a una carpeta de librería que tengas, asociada al proyecto de Silverlight, donde quieres usar la funcionalidad de Scripting.

En mi caso, el proyecto es ScriptNet y luego de copiar la dll en una carpeta de librería asociada al proyecto la referencié en el proyecto Silverlight.

ScriptingNet1

En el App.xaml, en su Code-Behind, en el constructor y antes de InitializeComponent, colocar el código:

RuntimeHost.Initialize();

 


Esta  instrucción inicializa la característica de Scripting, para que pueda ser usada en cualquier página del proyecto. Si deseas solo usar la característica de Scripting en una página o User Control dado, debes colocar la instrucción antes del InitializeComponent de tu página o UserControl.


Para mi caso, tengo la siguiente página:


ScriptingNet2


Como se puede apreciar, en el primer caso, en el resultado del click del botón Calcular dato, se realiza el cálculo sin la fórmula externalizada; sin embargo, el resultado del click del segundo botón Calcular  fórmula, se realiza con base en la fórmula que se encuentra en la caja de texto correspondiente a la misma. Lo que resuelve de forma apropiada el problema que tenía.


Observar, como los resultados son exactamente iguales.


Ahora, démosle una mirada a la implementación del click de cada botón.


ScriptingNet3


Este es el caso normal, aquí se llama al método RealizarOperacion:


ScriptingNet4


Como vemos, se obtiene la información para los términos  y luego se calcula su valor en base a la fórmula, pero ésta no se encuentra externalizada.


A continuación, veremos el segundo caso:


ScriptingNet5


Observar, como la implementación del click es casi idéntica al del primer caso, solo que acá se obtiene la formula de la caja de texto y ésta se le pasa como parámetro a otra sobrecarga del método RealizarOperacion:


ScriptingNet6


Fijarse, como el código de la definición de los términos que participan en la fórmula permanece igual y lo que resta es:




  1. Definir el contexto, para la definición de las variables a participar en la fórmula.


  2. Definir los valores de las variables, que participarán en la fórmula, a través de context.SetItem.


  3. Ejecutar el texto, teniendo en cuenta los valores de las variables definidas en el contexto. (Script.RunCode).


  4. Obtener el valor que quedó como resultado en alguno de los ítems definidos en el contexto. (context.GetItem).

Esto permite, la modificación de la fórmula, en cualquier momento y sin la afectación del código, lo que resuelve, perfectamente, el problema.


Veamos como, a continuación, se modifica la fórmula, sumando 10 y el resultado es el apropiado y el código de la realización de la operación no cambia:


ScriptingNet7


Listo, espero que les haya gustado y que les sirva tanto como a mí. Este Script.NET, amplia el rango de acción de Silverlight y colabora, para que la afirmación de que en Silverlight el límite es tu imaginación sea siempre vigente.

sábado, 14 de abril de 2012

Agregar controles dinámicamente a página ya diseñada

 

Hoy quiero compartir, algunos temas que aprendí y que pueden servirles de ayuda tanto como a mí.

La necesidad que tenía era colocar un control de forma dinámica a una página ya construida, con el propósito de dar avisos, visualmente, dada la información ingresada en ciertos controles enlazados a propiedades dadas (Vale la pena decir, que se usaba el patrón MVVM).

El primer tema a resolver era obtener el control asociado a la propiedad que cambiaba en el ViewModel, sin embargo, el patrón MVVM se creo con el propósito o idea de que el ViewModel no conociera los detalles asociados a la vista que se le asocia, para de esta forma garantizar el desacople necesario para el patrón.

Lo que se requería, entonces, era:

Dado el código:

 <TextBox x:Name="NombreTextBox" Text="{Binding Path=Persona.Nombre,Mode=TwoWay}" Grid.Column="1"></TextBox>

Con la propiedad Nombre, poder obtener que el nombre del control, en este caso NombreTextBox.


Por tanto, toda la información requerida para resolver la primera parte del problema se encontraba en la propia página XAML. Por tanto, necesitaba una forma para leer la información o el XAML asociado a una página dada y la encontré.


Se usa la clase XDocument de System.Xml.Linq, para cargar la información de la ruta donde se encuentra el XAML asociado a la página.


Así:

public VerXAML()
{
InitializeComponent();
}

private void ObtenerXAMLButton_Click(object sender, RoutedEventArgs e)
{
XDocument doc = XDocument.Load("/PruebasSilverligth;component/Blog/VerXAML.xaml");
ContenidoXAMLTextBox.Text = doc.ToString();
}

Fijarse como al método Load, se le indica la ruta donde se halla la página XAML, con la siguiente sintaxis:


“/<Nombre_Proyecto_Silverlight>;component/<Ruta_Completa_PaginaXAML>”


No obstante, puedes acceder de forma rápida para obtener la ruta de tu página, si en el constructor de la misma te ubicas sobre la llamada a InicializeComponent() y les das F12. Esto te lleva a un código auto generado, de donde puedes tomar el URL asociado a tu página:


AddCtrlDinamico1


AddCtrlDinamico2



Este código tan simple, te permite obtener el código XAML de tu página, como se ilustra a continuación:


AddCtrlDinamico3


Ahora era cuestión de buscar en el código XAML de la página, el control enlazado a una propiedad determinada.


Eso se logró con el siguiente método:

/// <summary>
///
Obtiene el nombre del control al que se le hace Binding de una propiedad determinada
/// </summary>
/// <param name="rutaPagina">
Ruta del XAML asociado a la página</param>
/// <param name="propiedad">
Es la propiedad del ViewModel asociado a la página a la que
/// se le hace Binding</param>
/// <returns>
El nombre del control</returns>
public static string ObtenerNombreControlAsociadoAPropiedad(string rutaPagina, string propiedad)
{
XDocument doc = XDocument.Load(rutaPagina);

XElement control = (from c in doc.Descendants()
where c.Attributes().Any(a => a.Value.Contains("Binding") && a.Value.Contains(propiedad))
select c).FirstOrDefault();
string nombreControl = (from a in control.Attributes()
where a.Name.ToString().Contains("Name")
select a.Value).FirstOrDefault();
return nombreControl;

}

Como puedes adivinar, el prerrequisito para que esto funcione es que los controles enlazados a propiedades tengan su respectivo nombre.


Una vez se tiene el nombre del control enlazado a la propiedad, se procede a buscarlo en la jerarquía de controles de la página, para colocar el control que requieras al lado de éste ( en mi caso, el control para la presentación de avisos). También, puedes eliminar el control que agregaste, cuando ya no lo requieras. Esto se logró con los siguientes métodos:

/// <summary>
///
Agrega un control dado al lado de un control de nombre dado que se encuentra colocado en un Panel Grid
/// </summary>
/// <param name="nombreControl">
Nombre del control al lado del cual se agregará el control dado</param>
/// <param name="elementoRaiz">
Nombre del Panel raiz que contiene la jerarquía de controles</param>
/// <param name="elementoAAgregar">
Control a agregar</param>
public static void AgregarControlToVisual(string nombreControl, UIElement elementoRaiz, UIElement elementoAAgregar)
{
Panel panel = elementoRaiz as Panel;
foreach (UIElement child in panel.Children)
{
if (child is Grid)
{
foreach (UIElement element in ((Panel)child).Children)
{
if (((FrameworkElement)element).Name.Equals(nombreControl))
{
Grid gridPadre = child as Grid;
if (gridPadre.Children.Contains(elementoAAgregar))
{
return;
}
gridPadre.ColumnDefinitions.Add(new ColumnDefinition());

Grid.SetRow((FrameworkElement)elementoAAgregar, Grid.GetRow((FrameworkElement)element));
Grid.SetColumn((FrameworkElement)elementoAAgregar, gridPadre.ColumnDefinitions.Count - 1);
gridPadre.Children.Add(elementoAAgregar);
return;
}
}
}
}
}
/// <summary>
///
Elimina un control dado al lado del control del nombre indicado que se encuentra en un Panel Grid
/// </summary>
/// <param name="nombreControl">
Nombre del control al lado del cual se encuentra el control a eliminar</param>
/// <param name="elementoRaiz">
Nombre del Panel raiz que contiene la jerarquía de controles</param>
/// <param name="elementoAEliminar">
Control a eliminar</param>
public static void EliminarControlFromVisual(string nombreControl, UIElement elementoRaiz, UIElement elementoAEliminar)
{
Panel panel = elementoRaiz as Panel;
foreach (UIElement child in panel.Children)
{
if (child is Grid)
{
foreach (UIElement element in ((Panel)child).Children)
{
if (((FrameworkElement)element).Name.Equals(nombreControl))
{
Grid gridPadre = child as Grid;
if (!gridPadre.Children.Contains(elementoAEliminar))
{
return;
}
gridPadre.Children.Remove(elementoAEliminar);
gridPadre.ColumnDefinitions.RemoveAt(gridPadre.ColumnDefinitions.Count - 1);
return;
}
}
}
}
}



Nota: Para la necesidad que tenía, los controles enlazados a las propiedades estaban ubicados, con la siguiente disposición:


Panel principal


…Grid


……..Control enlazado a propiedad


….Fin Grid


Fin Panel principal


Y para estructuras de organización de controles similares, funcionarán los métodos suministrados.


Ejemplo:


XAML:

<UserControl x:Class="PruebasSilverligth.Blog.PruebaHallarControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<
StackPanel x:Name="LayoutRoot" >
<
Grid x:Name="FormularioGrid" Background="White">
<
Grid.RowDefinitions>
<
RowDefinition Height="30"></RowDefinition>
<
RowDefinition Height="30"></RowDefinition>
<
RowDefinition Height="30"></RowDefinition>
<
RowDefinition Height="30"></RowDefinition>
<
RowDefinition Height="30"></RowDefinition>
<
RowDefinition Height="30"></RowDefinition>
</
Grid.RowDefinitions>
<
Grid.ColumnDefinitions>
<
ColumnDefinition></ColumnDefinition>
<
ColumnDefinition></ColumnDefinition>
</
Grid.ColumnDefinitions>
<
TextBlock x:Name="NombreTextBlock" Text="Nombre"></TextBlock>
<
TextBox x:Name="NombreTextBox" Text="{Binding Path=Persona.Nombre,Mode=TwoWay}" Grid.Column="1"></TextBox>
<
TextBlock x:Name="ApellidoTextBlock" Text="Apellido" Grid.Row="1"></TextBlock>
<
TextBox x:Name="ApellidoTextBox" Text="{Binding Path=Persona.Apellido,Mode=TwoWay}" Grid.Row="1" Grid.Column="1"></TextBox>
<
TextBlock x:Name="EdadTextBlock" Text="Edad" Grid.Row="2"></TextBlock>
<
TextBox x:Name="EdadTextBox" Text="{Binding Path=Persona.Edad,Mode=TwoWay}" Grid.Row="2" Grid.Column="1"></TextBox>
<
Button x:Name="GrabarButton" Content="Grabar" Grid.Row="3" Grid.ColumnSpan="2" Command="{Binding SaveCommand}"></Button>
<
Button x:Name="AgregarControlButton" Content="Agregar control" Grid.Row="4" Grid.ColumnSpan="2" Click="AgregarControlButton_Click"></Button>
<
Button x:Name="EliminarControlButton" Content="Eliminar control" Grid.Row="5" Grid.ColumnSpan="2" Click="EliminarControlButton_Click"></Button>
</
Grid>
</
StackPanel>
</
UserControl>


Code Behind:

public partial class PruebaHallarControl : UserControl
{
Button _botonAAgregar;
string _nombreControlAsoPropiedad;
public PruebaHallarControl()
{
InitializeComponent();
PruebaHallarControlViewModel viewModel = new PruebaHallarControlViewModel();
this.DataContext = viewModel;
_botonAAgregar = new Button(){Content="Botón agregado"};
_nombreControlAsoPropiedad = ObtenerNombreControlAsociadoAPropiedad("/PruebasSilverligth;component/Blog/PruebaHallarControl.xaml",
"Edad");
}

/// <summary>
///
Obtiene el nombre del control al que se le hace Binding de una propiedad determinada
/// </summary>
/// <param name="rutaPagina">
Ruta del XAML asociado a la página</param>
/// <param name="propiedad">
Es la propiedad del ViewModel asociado a la página a la que
/// se le hace Binding</param>
/// <returns>
El nombre del control</returns>
public static string ObtenerNombreControlAsociadoAPropiedad(string rutaPagina, string propiedad)
{
XDocument doc = XDocument.Load(rutaPagina);

XElement control = (from c in doc.Descendants()
where c.Attributes().Any(a => a.Value.Contains("Binding") && a.Value.Contains(propiedad))
select c).FirstOrDefault();
string nombreControl = (from a in control.Attributes()
where a.Name.ToString().Contains("Name")
select a.Value).FirstOrDefault();
return nombreControl;

}
/// <summary>
///
Agrega un control dado al lado de un control de nombre dado que se encuentra colocado en un Panel Grid
/// </summary>
/// <param name="nombreControl">
Nombre del control al lado del cual se agregará el control dado</param>
/// <param name="elementoRaiz">
Nombre del Panel raiz que contiene la jerarquía de controles</param>
/// <param name="elementoAAgregar">
Control a agregar</param>
public static void AgregarControlToVisual(string nombreControl, UIElement elementoRaiz, UIElement elementoAAgregar)
{
Panel panel = elementoRaiz as Panel;
foreach (UIElement child in panel.Children)
{
if (child is Grid)
{
foreach (UIElement element in ((Panel)child).Children)
{
if (((FrameworkElement)element).Name.Equals(nombreControl))
{
Grid gridPadre = child as Grid;
if (gridPadre.Children.Contains(elementoAAgregar))
{
return;
}
gridPadre.ColumnDefinitions.Add(new ColumnDefinition());

Grid.SetRow((FrameworkElement)elementoAAgregar, Grid.GetRow((FrameworkElement)element));
Grid.SetColumn((FrameworkElement)elementoAAgregar, gridPadre.ColumnDefinitions.Count - 1);
gridPadre.Children.Add(elementoAAgregar);
return;
}
}
}
}
}
/// <summary>
///
Elimina un control dado al lado del control del nombre indicado que se encuentra en un Panel Grid
/// </summary>
/// <param name="nombreControl">
Nombre del control al lado del cual se encuentra el control a eliminar</param>
/// <param name="elementoRaiz">
Nombre del Panel raiz que contiene la jerarquía de controles</param>
/// <param name="elementoAEliminar">
Control a eliminar</param>
public static void EliminarControlFromVisual(string nombreControl, UIElement elementoRaiz, UIElement elementoAEliminar)
{
Panel panel = elementoRaiz as Panel;
foreach (UIElement child in panel.Children)
{
if (child is Grid)
{
foreach (UIElement element in ((Panel)child).Children)
{
if (((FrameworkElement)element).Name.Equals(nombreControl))
{
Grid gridPadre = child as Grid;
if (!gridPadre.Children.Contains(elementoAEliminar))
{
return;
}
gridPadre.Children.Remove(elementoAEliminar);
gridPadre.ColumnDefinitions.RemoveAt(gridPadre.ColumnDefinitions.Count - 1);
return;
}
}
}
}
}

private void AgregarControlButton_Click(object sender, RoutedEventArgs e)
{

AgregarControlToVisual(_nombreControlAsoPropiedad, LayoutRoot, _botonAAgregar);
}

private void EliminarControlButton_Click(object sender, RoutedEventArgs e)
{
EliminarControlFromVisual(_nombreControlAsoPropiedad, LayoutRoot, _botonAAgregar);
}

}


Y se obtiene esta funcionalidad:


AddCtrlDinamico4


Espero que les sirva.

domingo, 1 de abril de 2012

Controles que muestran colecciones de objetos – ItemsControl

Los controles que muestran colecciones de objetos son indispensables en nuestras aplicaciones. Silverlight incluye, entre otros, los siguientes: ComboBox, ListBox, TabControl y probablemente el más importante de todos, la DataGrid. La DataGrid puede ser utilizada para mostrar los datos en una representación similar a Excel.

En esta serie de cápsulas entraremos a estudiar este tipo de controles e iniciaremos con el ItemsControl.

El ItemsControl es un control genérico para mostrar lista de datos.

Se puede utilizar para presentar un conjunto fijo de elementos o para mostrar una lista obtenida del enlace de datos a un objeto.

El ItemsControl permite definir una plantilla para definir el panel que se usará para los items (StackPanel, Canvas, Grid, etc.) a través de la propiedad ItemsPanel donde se define el ItemsPanelTemplate, así como una plantilla para definir la apariencia con que se presentarán los datos, usando la propiedad ItemTemplate, en donde se define el DataTemplate.

Si deseas conocer más información acerca de este control visita:

http://msdn.microsoft.com/es-es/library/system.windows.controls.itemscontrol(VS.95).aspx

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

miércoles, 14 de marzo de 2012

Silverlight ControlGridHelper–Objeto que permite redistribuir la información de la Grid, cuando hay elementos con visibilidad colapsada.

 

Como parte de un desarrollo, es necesario mostrar o no información, dependiendo de la opción seleccionada por el usuario. Ahora, para la ubicación de la información en la página XAML, se utilizó el control Panel Grid.

Como se ve en el siguiente ejemplo:

ControlGridHelper1

Si dinámicamente, se debe ocultar el botón 11, en la pantalla, simplemente queda el espacio en blanco, como se muestra a continuación:

ControlGridHelper2

El ControlGridHelper, permite redistribuir los controles restantes, para ocupar los espacios vacíos. Por ejemplo, en el escenario mostrado, podemos indicarle al ControlGridHelper que nos reacomode los controles por fila, así:

ControlGridHelper.Instance.ReacomodarControlesGrid(LayoutRoot,false);

Y el resultado es este:


ControlGridHelper3


Es decir, se ubica en la celda con el espacio en blanco y desplaza los controles por la fila hacia la izquierda:


ControlGridHelper4





También se puede lograr, el reacomodo, por columnas así:


Tenemos la situación original:


ControlGridHelper1


Ahora, supongamos que el botón 2, queda oculto y que el reacomodo se hace por columnas. Eso lo indicamos de esta forma:

ControlGridHelper.Instance.ReacomodarControlesGrid(LayoutRoot,true);

Y el resultado es este:


ControlGridHelper5


Es decir, se ubica en la celda con el espacio en blanco y desplaza los controles por la columna hacia arriba:


ControlGridHelper6



Utilizar el objeto ControlGridHelper, es muy sencillo, solo es llamar a su método ReacomodarControlesGrid y pasarle como parámetros: la Grid, cuyos controles se reacomodarán  y la indicación de si el reacomodo será por filas o por columnas ( tu decides).


El propósito del objeto ControlGridHelper es ayudar a reacomodar la información en la Grid, para que la presentación de ésta sea más agradable, en la situación ilustrada de ocultación dinámica de controles en el Grid.


Espero que les sirva, aquí les dejo el código:

public sealed class ControlGridHelper
{
/// <summary>
///
Contiene información adicional de ayuda, para la manipulación de la
/// información en la grid.
/// </summary>
private class GridHelper
{
/// <summary>
///
Almacena el identificador de la fila
/// </summary>
private int _fila;
/// <summary>
///
Almacena el identificador de la columna
/// </summary>
private int _col;

/// <summary>
///
Almacena el número de controles eliminados en la fila
/// </summary>
private int _numeroControlesEliminadosFila;
/// <summary>
///
Almacena el número de controles eliminados en la columna
/// </summary>
private int _numeroControlesEliminadosCol;
/// <summary>
///
Permite obtener o asignar el identificador de la fila
/// </summary>
public int Fila
{
get
{
return _fila;
}
set
{
_fila = value;
}
}
/// <summary>
///
Permite obtener o asignar el identificador de la columna
/// </summary>
public int Columna
{
get
{
return _col;
}
set
{
_col = value;
}
}
/// <summary>
///
Permite obtener o asignar el número de controles eliminados de la
/// fila
/// </summary>
public int NumeroControlesEliminadosFila
{
get
{
return _numeroControlesEliminadosFila;
}
set
{
_numeroControlesEliminadosFila = value;
}
}
/// <summary>
///
Permite obtener o asignar el número de controles eliminados de la
/// columna
/// </summary>
public int NumeroControlesEliminadosCol
{
get
{
return _numeroControlesEliminadosCol;
}
set
{
_numeroControlesEliminadosCol = value;
}
}
/// <summary>
///
Incrementa el número de controles eliminados en la
/// fila
/// </summary>
/// <param name="fila">
Identificador de la fila</param>
public void IncrementarNumeroControlesEliminadosFila(int fila)
{
if (_fila == fila)
{
_numeroControlesEliminadosFila++;
}
}
/// <summary>
///
Incrementa el número de controles eliminados en la
/// columna
/// </summary>
/// <param name="col">
Identificador de la columna</param>
public void IncrementarNumeroControlesEliminadosCol(int col)
{
if (_col == col)
{
_numeroControlesEliminadosCol++;
}
}
};

/// <summary>
///
Instancia privada para la implementación del patrón Singleton
/// </summary>
private static readonly ControlGridHelper instance = new ControlGridHelper();

/// <summary>
///
Constructor privado, usada por la implementación del patrón Singleton
/// </summary>
private ControlGridHelper() { }

/// <summary>
///
Instancia del Helper, para poder usar los métodos
/// </summary>
public static ControlGridHelper Instance
{
get
{
return instance;
}
}


/// <summary>
///
Reacomoda los controles en un control Grid, ya sea por columnas o por filas.
/// </summary>
/// <param name="gridControl">
Es el control Grid</param>
/// <param name="porColumna">
Indica si el reacomodo se hará por columnas o por filas</param>
public void ReacomodarControlesGrid(Grid gridControl, bool porColumna = true)
{
int col = -1;
int fila = -1;
//Los controles que se encuentran con visibilidad Collapset al
//final son eliminados para evitar generacion de excepciones.
List<object> controlesARemover = new List<object>();
List<GridHelper> listaGridHelper = CargarListaGridHelper(gridControl);
for (int contador = 0; contador < gridControl.Children.Count; contador++)
{
var control = gridControl.Children[contador];

if (control.Visibility == Visibility.Collapsed)
{
fila = Convert.ToInt32(control.GetValue(Grid.RowProperty));
col = Convert.ToInt32(control.GetValue(Grid.ColumnProperty));
//Se agrega el control a la lista de los que se eliminarán.
controlesARemover.Add(control);
if (porColumna)
{
//Se reacomoda la información de la columna
ReacomodarControlesPorColumna(gridControl, col, fila);
}
else
{
//Se reacomoda la información de la fila
ReacomodarControlesPorFila(gridControl, col, fila);
}
}
}

//Se remueven los controles, por si se vuelve a ejecutar el código no
//se produzca ningún error.
foreach (var control in controlesARemover)
{
gridControl.Children.Remove((UIElement)control);
}

if (porColumna)
{
EliminarColumnasSinControles(gridControl, listaGridHelper);
}
else
{
//Es por fila
EliminarFilasSinControles(gridControl, listaGridHelper);
}

//Pueden quedar filas sin controles

for (int contador = gridControl.RowDefinitions.Count - 1; contador >= 0; contador--)
{
if (!ValidarFilaConControles(gridControl, contador))
{
gridControl.RowDefinitions.RemoveAt(contador);
}
}
//Pueden quedar columnas sin controles
for (int contador = gridControl.ColumnDefinitions.Count - 1; contador >= 0; contador--)
{
if (!ValidarColumnaConControles(gridControl, contador))
{
gridControl.ColumnDefinitions.RemoveAt(contador);
}
}
}

/// <summary>
///
Verifica si una fila tiene o no controles
/// </summary>
/// <param name="gridControl">
Es el control Grid</param>
/// <param name="fila">
Es la fila que se verifica</param>
/// <returns>
True o False dependiendo de lo encontrado</returns>
private bool ValidarFilaConControles(Grid gridControl, int fila)
{
for (int contador = 0; contador < gridControl.Children.Count; contador++)
{
var control = gridControl.Children[contador];
if (fila == Convert.ToInt32(control.GetValue(Grid.RowProperty)))
{
return true;
}

}
return false;
}
/// <summary>
///
Verifica si una columna tiene o no controles
/// </summary>
/// <param name="gridControl">
Es el control Grid</param>
/// <param name="col">
Es la columna que se verifica</param>
/// <returns>
True o False dependiendo de lo encontrado</returns>
private bool ValidarColumnaConControles(Grid gridControl, int col)
{
for (int contador = 0; contador < gridControl.Children.Count; contador++)
{
var control = gridControl.Children[contador];
if (col == Convert.ToInt32(control.GetValue(Grid.ColumnProperty)))
{
return true;
}

}
return false;
}

/// <summary>
///
Carga el listado de objetos GridHelper con la información apropiada
/// </summary>
/// <param name="gridControl">
Es el control Grid</param>
/// <returns>
Lista de objetos GridHelper</returns>
private List<GridHelper> CargarListaGridHelper(Grid gridControl)
{
int col = -1;
int fila = -1;
List<GridHelper> listaGridHelper = new List<GridHelper>();
for (int contador = 0; contador < gridControl.Children.Count; contador++)
{
var control = gridControl.Children[contador];
col = Convert.ToInt32(control.GetValue(Grid.ColumnProperty));
if (listaGridHelper.Where(item => item.Columna == col).ToList().Count == 0)
{
listaGridHelper.Add(new GridHelper() { Columna = col });
}
fila = Convert.ToInt32(control.GetValue(Grid.RowProperty));
if (listaGridHelper.Where(item => item.Fila == fila).ToList().Count == 0)
{
listaGridHelper.Add(new GridHelper() { Fila = fila });
}


if (control.Visibility == Visibility.Collapsed)
{
fila = Convert.ToInt32(control.GetValue(Grid.RowProperty));
col = Convert.ToInt32(control.GetValue(Grid.ColumnProperty));
//Se incrementa el número de controles que se eliminan de la
//columna
listaGridHelper.Where(item => item.Columna == col).FirstOrDefault().
IncrementarNumeroControlesEliminadosCol(col);

//Se incrementa el número de controles que se eliminan de la
//fila
listaGridHelper.Where(item => item.Fila == fila).FirstOrDefault().
IncrementarNumeroControlesEliminadosFila(fila);
}
}

return listaGridHelper;
}

/// <summary>.
/// Elimina las columnas que quedan sin controles
/// </summary>
/// <param name="gridControl">
Es el control grid</param>
/// <param name="listaGridHelper">
Es la lista de información de ayuda de la Grid</param>
private void EliminarColumnasSinControles(Grid gridControl, List<GridHelper> listaGridHelper)
{
foreach (var item in listaGridHelper)
{

if (item.NumeroControlesEliminadosCol == gridControl.RowDefinitions.Count)
{
if (item.Columna < gridControl.ColumnDefinitions.Count - 1)
{
//Se mueven los controles de las otras columnas hacia la
//que se elimina
DesplazarControlesUnaColumna(gridControl, item.Columna);
}
gridControl.ColumnDefinitions.RemoveAt(item.Columna);

}

}

}
/// <summary>.
/// Elimina las filas que quedan sin controles
/// </summary>
/// <param name="gridControl">
Es el control grid</param>
/// <param name="listaGridHelper">
Es la lista de información de ayuda de la Grid</param>
private void EliminarFilasSinControles(Grid gridControl, List<GridHelper> listaGridHelper)
{
foreach (var item in listaGridHelper)
{
if (item.NumeroControlesEliminadosFila == gridControl.ColumnDefinitions.Count)
{
if (item.Fila < gridControl.RowDefinitions.Count - 1)
{
//Se mueven los controles de las otras filas hacia la
//que se elimina
DesplazarControlesUnaFila(gridControl, item.Fila);
}
gridControl.RowDefinitions.RemoveAt(item.Fila);

}
}
}
/// <summary>
///
Mueve los controles recursivamente hacia la columna que se encuentra
/// vacía. Asegurandose, de esta forma, que la columna que quede sin controles
/// sea la última.
/// </summary>
/// <param name="gridControl">
Control Grid</param>
/// <param name="col">
Columna que se encuentra sin controles</param>
private void DesplazarControlesUnaColumna(Grid gridControl, int col)
{
foreach (var control in gridControl.Children)
{
if (Convert.ToInt32(control.GetValue(Grid.ColumnProperty)) > col)
{
control.SetValue(Grid.ColumnProperty, Convert.ToInt32(control.GetValue(Grid.ColumnProperty)) - 1);
}
}
}

/// <summary>
///
Mueve los controles recursivamente hacia la fila que se encuentra
/// vacía. Asegurandose, de esta forma, que la fila que quede sin controles
/// sea la última.
/// </summary>
/// <param name="gridControl">
Control Grid</param>
/// <param name="fila">
Fila que se encuentra sin controles</param>
private void DesplazarControlesUnaFila(Grid gridControl, int fila)
{
foreach (var control in gridControl.Children)
{
if (Convert.ToInt32(control.GetValue(Grid.RowProperty)) > fila)
{
control.SetValue(Grid.RowProperty, Convert.ToInt32(control.GetValue(Grid.RowProperty)) - 1);
}
}
}
/// <summary>
///
Mueve reiteradamente los controles de una columna, hacia arriba,
/// asegurandose que ocupen la posición que ocupaba un control con
/// visibilidad Collapsed. De esta forma, se asegura, que la última
/// fila de la columna queda sin controles.
/// </summary>
/// <param name="gridControl">
Control Grid</param>
/// <param name="col">
Columna que posee el control de visibilidad Collapsed</param>
/// <param name="fila">
Fila que posee el control de visibilidad Collapsed</param>
private void ReacomodarControlesPorColumna(Grid gridControl, int col, int fila)
{
foreach (var control in gridControl.Children)
{
if (Convert.ToInt32(control.GetValue(Grid.ColumnProperty)) == col &&
Convert.ToInt32(control.GetValue(Grid.RowProperty)) > fila)
{
control.SetValue(Grid.RowProperty, Convert.ToInt32(control.GetValue(Grid.RowProperty)) - 1);
}
}
}

/// <summary>
///
Mueve reiteradamente los controles de una fila, hacia la izquierda,
/// asegurandose que ocupen la posición que ocupaba un control con
/// visibilidad Collapsed. De esta forma, se asegura, que la última
/// columna de la fila queda sin controles.
/// </summary>
/// <param name="gridControl">
Control Grid</param>
/// <param name="col">
Columna que posee el control de visibilidad Collapsed</param>
/// <param name="fila">
Fila que posee el control de visibilidad Collapsed</param>
private void ReacomodarControlesPorFila(Grid gridControl, int col, int fila)
{
foreach (var control in gridControl.Children)
{
if (Convert.ToInt32(control.GetValue(Grid.RowProperty)) == fila &&
Convert.ToInt32(control.GetValue(Grid.ColumnProperty)) > col)
{
control.SetValue(Grid.ColumnProperty, Convert.ToInt32(control.GetValue(Grid.ColumnProperty)) - 1);
}
}
}


}