<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://geeks.ms/utility/FeedStylesheets/atom.xsl" media="screen"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang=""><title type="html">El aprendiz de brujo </title><subtitle type="html">El blog de Luis Miguel Blanco con hechizos, conjuros y sortilegios varios sobre la plataforma .NET
&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;img src="http://geeks.ms/blogs/lmblanco/ImgEnl/HatWand.jpg" style="border-style:none;vertical-align:middle;" alt="" /&gt;
</subtitle><id>http://geeks.ms/blogs/lmblanco/atom.aspx</id><link rel="alternate" type="text/html" href="http://geeks.ms/blogs/lmblanco/default.aspx" /><link rel="self" type="application/atom+xml" href="http://geeks.ms/blogs/lmblanco/atom.aspx" /><generator uri="http://communityserver.org" version="4.1.31106.3070">Community Server</generator><updated>2010-08-26T13:55:00Z</updated><entry><title>Pirámides de población superpuestas con PowerPivot</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2012/01/19/pir-225-mides-de-poblaci-243-n-superpuestas-con-powerpivot.aspx" /><id>/blogs/lmblanco/archive/2012/01/19/pir-225-mides-de-poblaci-243-n-superpuestas-con-powerpivot.aspx</id><published>2012-01-19T22:20:00Z</published><updated>2012-01-19T22:20:00Z</updated><content type="html">&lt;p&gt;En los art&amp;iacute;culos que dedic&amp;aacute;bamos a la creaci&amp;oacute;n de una pir&amp;aacute;mide de poblaci&amp;oacute;n empleando PowerPivot (&lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/08/18/pir-225-mides-de-poblaci-243-n-con-powerpivot-preparaci-243-n-del-entorno-de-datos-1.aspx"&gt;parte1&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/08/21/pir-225-mides-de-poblaci-243-n-con-powerpivot-creaci-243-n-del-gr-225-fico-y-2.aspx"&gt;parte2&lt;/a&gt;), pudimos comprobar la potencia que este complemento para Excel proporciona a aquellos usuarios encargados de realizar determinados an&amp;aacute;lisis de informaci&amp;oacute;n sobre una base de datos de contenido demogr&amp;aacute;fico.&lt;/p&gt;
&lt;p&gt;Continuando la l&amp;iacute;nea de trabajo abierta en aquellos art&amp;iacute;culos, en esta ocasi&amp;oacute;n abordaremos el desarrollo de pir&amp;aacute;mides de poblaci&amp;oacute;n superpuestas, un aspecto del trabajo con pir&amp;aacute;mides demogr&amp;aacute;ficas, que consiste en observar y analizar las diferencias de estructura por sexo y edad existentes entre dos poblaciones, mediante la comparaci&amp;oacute;n directa de sus respectivas pir&amp;aacute;mides.&lt;/p&gt;
&lt;p&gt;Antes de proseguir quisiera reiterar mi agradecimiento a Ricard G&amp;egrave;nova Maleras, dem&amp;oacute;grafo especializado en an&amp;aacute;lisis poblacionales sanitarios, perteneciente al Servicio de Informes de Salud y Estudios (Subdirecci&amp;oacute;n de Promoci&amp;oacute;n de la Salud y Prevenci&amp;oacute;n, DG Atenci&amp;oacute;n Primaria, Consejer&amp;iacute;a Sanidad CM), por su inestimable labor de revisi&amp;oacute;n y orientaci&amp;oacute;n en todos aquellos conceptos sobre creaci&amp;oacute;n de pir&amp;aacute;mides demogr&amp;aacute;ficas, que tan valiosos han resultado en la elaboraci&amp;oacute;n del presente y los anteriores art&amp;iacute;culos que hemos publicado acerca de este mismo tema en el blog.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Breve introducci&amp;oacute;n a las pir&amp;aacute;mides de poblaci&amp;oacute;n superpuestas&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si queremos describir gr&amp;aacute;ficamente este escenario de trabajo, en primer lugar tomaremos las pir&amp;aacute;mides de las poblaciones a comparar...&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_01.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_01.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;...y a continuaci&amp;oacute;n colocaremos una pir&amp;aacute;mide sobre la otra, de forma que podamos apreciar y analizar las diferencias de poblaci&amp;oacute;n existentes entre ambas, finalizando as&amp;iacute; la operaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_02.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_02.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Si se trata de dos poblaciones est&amp;aacute;ticas, la tarea no reviste mayor complejidad que la de rellenar las celdas de la hoja Excel con las cifras de las poblaciones correspondientes, y preparar el gr&amp;aacute;fico con forma de pir&amp;aacute;mide que combine los valores. Sin embargo, supongamos que tenemos una poblaci&amp;oacute;n base o de referencia, perteneciente al total de individuos de una regi&amp;oacute;n, y queremos establecer comparaciones entre ese total y una clasificaci&amp;oacute;n de los subgrupos en que dicha poblaci&amp;oacute;n puede ser dividida, como por ejemplo, las zonas geogr&amp;aacute;ficas o de atenci&amp;oacute;n sanitaria.&lt;/p&gt;
&lt;p&gt;Si el n&amp;uacute;mero de zonas es muy elevado, aumentar&amp;aacute; la cantidad de c&amp;aacute;lculos y pir&amp;aacute;mides de subgrupos que necesitaremos elaborar para comparar con la pir&amp;aacute;mide principal de referencia, increment&amp;aacute;ndose la complejidad del an&amp;aacute;lisis demogr&amp;aacute;fico a realizar.&lt;/p&gt;
&lt;p&gt;Es en este punto del problema donde entra en liza PowerPivot, ya que si lo utilizamos para gestionar los datos de las poblaciones con las que debemos trabajar, simplificaremos en gran medida la elaboraci&amp;oacute;n de las pir&amp;aacute;mides de poblaci&amp;oacute;n, as&amp;iacute; como su posterior fase de an&amp;aacute;lisis.&lt;/p&gt;
&lt;p&gt;Aprovechando la pir&amp;aacute;mide desarrollada en los art&amp;iacute;culos mencionados anteriormente, y&amp;nbsp; plasmada en el archivo PiramidePoblacion.xlsx, utilizaremos dicho escenario de trabajo como punto de partida para elaborar, en primer lugar, las pir&amp;aacute;mides de poblaci&amp;oacute;n de las distintas zonas sanitarias; pasando a continuaci&amp;oacute;n a crear la pir&amp;aacute;mide de referencia, que representa a la poblaci&amp;oacute;n de la Comunidad de Madrid.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Las pir&amp;aacute;mides de zonificaci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;A simple vista, esta tarea puede parecer la m&amp;aacute;s complicada, debido a que el objetivo de la misma consiste en crear una pir&amp;aacute;mide por cada una de las zonas sanitarias de la poblaci&amp;oacute;n que estamos manejando.&lt;/p&gt;
&lt;p&gt;Nada m&amp;aacute;s lejos de la realidad sin embargo, puesto que si hemos seguido los art&amp;iacute;culos ya comentados sobre creaci&amp;oacute;n de pir&amp;aacute;mides, nos habremos dado cuenta de que ese trabajo ya lo tenemos hecho en el archivo PiramidePoblacion.xlsx, creado como ejercicio de ejemplo de dichos art&amp;iacute;culos, gracias al empleo de una segmentaci&amp;oacute;n basada en la tabla Zona del modelo de datos de PowerPivot.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_03.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_03.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;No obstante, con el fin de reorganizar los nombres que utilizaremos en este art&amp;iacute;culo, vamos a eliminar las medidas y el gr&amp;aacute;fico de la pir&amp;aacute;mide que inicialmente hab&amp;iacute;amos creado para la tabla din&amp;aacute;mica. Tambi&amp;eacute;n cambiaremos, en la ventana de PowertPivot, el nombre de la tabla Poblacion por PoblacionZonas, haciendo clic derecho en la pesta&amp;ntilde;a correspondiente a la tabla, y eligiendo la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Cambiar nombre&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_04.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_04.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n crearemos de nuevo las medidas de la tabla PoblacionZonas, con los siguientes nombres y expresiones en lenguaje DAX.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;// PoblacionZonasSuma&lt;/p&gt;
&lt;p&gt;=SUM([Sexo_Codigo])&lt;/p&gt;
&lt;p&gt;// PoblacionZonasTotal&lt;/p&gt;
&lt;p&gt;=CALCULATE(COUNTROWS(PoblacionZonas),ALL(Edad),ALL(Sexo))&lt;/p&gt;
&lt;p&gt;// PoblacionZonasPorcentaje&lt;/p&gt;
&lt;p&gt;=[PoblacionZonasSuma] / [PoblacionZonasTotal]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_05.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_05.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La forma de crear y configurar el gr&amp;aacute;fico de pir&amp;aacute;mide para estas poblaciones ser&amp;aacute; la misma que en los art&amp;iacute;culos ya indicados, con la excepci&amp;oacute;n del borde de las barras, a las que en esta ocasi&amp;oacute;n asignaremos el color blanco, con un ancho de 2 puntos entre las mismas. Recordemos que para dar formato a las barras haremos clic derecho en cualquiera de ellas, seleccionando la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Dar formato a serie de datos&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_06.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_06.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En la siguiente figura podemos observar el gr&amp;aacute;fico con las modificaciones que acabamos de comentar (incluyendo la segmentaci&amp;oacute;n por el campo Zona_DS de la tabla Zona), mostrando&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; la pir&amp;aacute;mide de una de las zonas disponibles.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_07.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_07.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;La pir&amp;aacute;mide de referencia&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;El siguiente paso consistir&amp;aacute; en a&amp;ntilde;adir al gr&amp;aacute;fico actual la pir&amp;aacute;mide que representar&amp;aacute; al total de la poblaci&amp;oacute;n, para lo cual nos situaremos en la ventana de PowerPivot, donde repetiremos el proceso de agregaci&amp;oacute;n de la tabla Poblacion desde la base de datos origen hasta el modelo de datos de PowerPivot; pero en esta ocasi&amp;oacute;n daremos el nombre PoblacionReferencia a la tabla en PowerPivot, creando tambi&amp;eacute;n la columna calculada Sexo_Codigo con la expresi&amp;oacute;n DAX: &amp;nbsp;&amp;quot;=IF([Sexo_ID] = &amp;quot;M&amp;quot;, 1, -1)&amp;quot;, ya que igualmente necesitaremos sumar la poblaci&amp;oacute;n en funci&amp;oacute;n del sexo de los individuos.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_08.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_08.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Tras esta operaci&amp;oacute;n crearemos las oportunas relaciones entre ambas tablas de poblaci&amp;oacute;n y el resto, quedando el resultado mostrado por la siguiente figura.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_09.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_09.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n volveremos a la ventana de Excel, donde haremos clic en el bot&amp;oacute;n &amp;quot;Actualizar&amp;quot; de la ventana &amp;quot;Lista de campos de PowerPivot&amp;quot;, para que se refresque su contenido, y se incorpore la tabla PoblacionReferencia que acabamos de agregar a la ventana de PowerPivot.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_10.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_10.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En cuanto a las medidas necesarias para generar la pir&amp;aacute;mide correspondiente a esta poblaci&amp;oacute;n de referencia, en el siguiente bloque de c&amp;oacute;digo se muestran las expresiones DAX a utilizar para su creaci&amp;oacute;n.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;// PoblacionReferenciaSuma&lt;/p&gt;
&lt;p&gt;=CALCULATE(SUM([Sexo_Codigo]),ALL(Zona))&lt;/p&gt;
&lt;p&gt;// PoblacionReferenciaTotal&lt;/p&gt;
&lt;p&gt;=CALCULATE(COUNTROWS(PoblacionReferencia),ALL(Edad),ALL(Sexo),ALL(Zona))&lt;/p&gt;
&lt;p&gt;// PoblacionReferenciaPorcentaje&lt;/p&gt;
&lt;p&gt;=[PoblacionReferenciaSuma] / [PoblacionReferenciaTotal]&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Comparadas las medidas de la tabla PoblacionZonas y PoblacionReferencia, encontramos en estas &amp;uacute;ltimas una importante diferencia dentro de las operaciones encargadas de sumar la poblaci&amp;oacute;n y calcular su total, consistente en el uso de la funci&amp;oacute;n ALL aplicada a la tabla Zona, la cual es pasada como par&amp;aacute;metro. En la medida PoblacionReferenciaSuma utilizaremos, adem&amp;aacute;s, la funci&amp;oacute;n CALCULATE, para que la operaci&amp;oacute;n de suma sobre la tabla de poblaci&amp;oacute;n de referencia se efect&amp;uacute;e correctamente.&lt;/p&gt;
&lt;p&gt;La funci&amp;oacute;n ALL, cuando interviene en una expresi&amp;oacute;n DAX utilizada para construir una medida calculada que empleamos, por ejemplo, en una tabla din&amp;aacute;mica, anula aquellos filtros aplicados en la tabla din&amp;aacute;mica, que est&amp;eacute;n relacionados con la tabla pasada como par&amp;aacute;metro a la funci&amp;oacute;n ALL, y que en nuestro caso, como ya hemos mencionado, afecta a la tabla Zona.&lt;/p&gt;
&lt;p&gt;Para comprobar este comportamiento, que al mismo tiempo dar&amp;aacute; como resultado la pir&amp;aacute;mide de referencia, en la ventana de campos de PowerPivot arrastraremos el campo PoblacionReferenciaPorcentaje hasta el panel Valores. Esto producir&amp;aacute; la inserci&amp;oacute;n, en la tabla din&amp;aacute;mica, de nuevas columnas para dicha medida; y en el gr&amp;aacute;fico de pir&amp;aacute;mide, de barras para representar las nuevas cifras de poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_11.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_11.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Como siguiente paso aplicaremos el formato de porcentaje a las nuevas columnas de cifras de la tabla din&amp;aacute;mica, y a continuaci&amp;oacute;n haremos clic derecho en una de las nuevas barras de poblaci&amp;oacute;n del gr&amp;aacute;fico, seleccionando la opci&amp;oacute;n &amp;quot;Dar formato a serie de datos&amp;quot;; acci&amp;oacute;n esta que abrir&amp;aacute; la ventana del mismo nombre, donde modificaremos las siguientes propiedades/valores.&lt;/p&gt;
&lt;p&gt;--Relleno: Sin Relleno.&lt;/p&gt;
&lt;p&gt;--Color del borde: L&amp;iacute;nea s&amp;oacute;lida, color negro.&lt;/p&gt;
&lt;p&gt;--Estilos de borde: Ancho de 1 punto.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_12.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_12.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Repitiendo esta misma operaci&amp;oacute;n sobre la otra barra de datos del gr&amp;aacute;fico completaremos la configuraci&amp;oacute;n visual de la nueva pir&amp;aacute;mide de poblaci&amp;oacute;n de referencia, que quedar&amp;aacute; superpuesta a la pir&amp;aacute;mide por zonas, logrando as&amp;iacute; nuestro objetivo. Este resultado nos permitir&amp;aacute; apreciar las diferencias entre los dos tipos de poblaci&amp;oacute;n, facilitando su an&amp;aacute;lisis.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_13.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201201/PiramidesPoblacionSuperpuestasPowerPivot_5F00_13.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Llegados a este punto damos&amp;nbsp; por concluido el presente art&amp;iacute;culo sobre construcci&amp;oacute;n de pir&amp;aacute;mides de poblaci&amp;oacute;n superpuestas, empleando PowerPivot como herramienta para modelar nuestros datos. En un pr&amp;oacute;ximo art&amp;iacute;culo abordaremos el desarrollo de pir&amp;aacute;mides acumuladas, una variedad de pir&amp;aacute;mide poblacional en la que las barras de la pir&amp;aacute;mide aportan mayor informaci&amp;oacute;n, gracias a que permiten la inclusi&amp;oacute;n de una categor&amp;iacute;a adicional de clasificaci&amp;oacute;n.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=202891" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="PowerPivot" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /></entry><entry><title>Optimizando la creación de estructuras de bases de datos en archivos de script mediante SSIS</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/10/15/optimizando-la-creaci-243-n-de-estructuras-de-bases-de-datos-en-archivos-de-script-mediante-ssis.aspx" /><id>/blogs/lmblanco/archive/2011/10/15/optimizando-la-creaci-243-n-de-estructuras-de-bases-de-datos-en-archivos-de-script-mediante-ssis.aspx</id><published>2011-10-15T09:43:00Z</published><updated>2011-10-15T09:43:00Z</updated><content type="html">&lt;p&gt;En el art&amp;iacute;culo &amp;quot;Utilizando SSIS para crear scripts de respaldo con la estructura de la base de datos&amp;quot; (&lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/10/02/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-1.aspx"&gt;parte 1&lt;/a&gt; - &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/10/03/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-y-2.aspx"&gt;parte 2&lt;/a&gt;), publicado con anterioridad en este blog, dej&amp;aacute;bamos pendiente de desarrollar una mejora que nos permitiera acelerar los tiempos de creaci&amp;oacute;n de los archivos de script, ya que el uso de algunas colecciones proporcionadas por la clase Database, m&amp;aacute;s concretamente Views, StoredProcedures y UserDefinedFunctions, al contener una importante cantidad de objetos del sistema, provocaba que el tiempo de ejecuci&amp;oacute;n del proceso se extendiese m&amp;aacute;s de lo necesario, en el caso de que no necesit&amp;aacute;ramos a&amp;ntilde;adir al script tales tipos de objetos.&lt;/p&gt;
&lt;p&gt;Por tal motivo, la finalidad del presente art&amp;iacute;culo ser&amp;aacute; ofrecer una soluci&amp;oacute;n a dicho problema, exponiendo una t&amp;eacute;cnica mediante la cual conseguiremos reducir los mencionados tiempos de ejecuci&amp;oacute;n. &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creaci&amp;oacute;n del proyecto de Integration Services&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Como gestor de datos utilizaremos &lt;a href="https://www.microsoft.com/betaexperience/pd/SQLDCTP3CTA/enus/"&gt;SQL Server Denali CTP3&lt;/a&gt;, y como entorno de desarrollo &amp;quot;SQL Server Business Intelligence Development Studio&amp;quot; (SSBIDS), con el que crearemos un nuevo proyecto de tipo &amp;quot;Integration Services Project&amp;quot; al que daremos el nombre EstructurasBBDDOptimizado (este proyecto de ejemplo puede descargarse en el siguiente &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201110/EstructurasBBDDOptimizadoZip.txt"&gt;enlace&lt;/a&gt;). Para m&amp;aacute;s detalles acerca de la configuraci&amp;oacute;n del proyecto: paquete de integraci&amp;oacute;n .dtsx, variables, referencias a ensamblados, etc., consultar el proyecto desarrollado en el art&amp;iacute;culo mencionado al comienzo, ya que su modo de creaci&amp;oacute;n es equivalente. En cuanto al c&amp;oacute;digo fuente del paquete, utilizaremos como punto de partida el existente en dicho proyecto, sobre el que progresivamente iremos realizando las modificaciones necesarias.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Las vistas INFORMATION_SCHEMA.XXX&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si queremos averiguar cu&amp;aacute;les son las vistas que el usuario ha creado en una base de datos, tenemos a nuestra disposici&amp;oacute;n la vista del sistema INFORMATION_SCHEMA.VIEWS, que podemos localizar en el nodo &amp;quot;Views | System Views&amp;quot; de SQL Server Management Studio.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/OptimizandoCreacionScriptsEstructuraBDSSIS_5F00_01.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/OptimizandoCreacionScriptsEstructuraBDSSIS_5F00_01.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una consulta sobre esta vista nos revelar&amp;aacute;, a trav&amp;eacute;s de sus campos TABLE_NAME y TABLE_SCHEMA, el nombre y esquema respectivamente de las vistas de usuario de la base de datos a la que estemos conectados.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/OptimizandoCreacionScriptsEstructuraBDSSIS_5F00_02.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/OptimizandoCreacionScriptsEstructuraBDSSIS_5F00_02.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;De igual manera ocurre para los procedimientos almacenados y funciones, cuyos nombres y esquemas podemos encontrar en los campos ROUTINE_NAME y ROUTINE_SCHEMA de INFORMATION_SCHEMA.ROUTINES, otra vista del sistema, en la que para diferenciar el tipo de objeto emplearemos el campo ROUTINE_TYPE, comprobando que su valor sea &amp;quot;PROCEDURE&amp;quot; o &amp;quot;FUNCTION&amp;quot;.&lt;/p&gt;
&lt;p&gt;Utilizando las anteriores vistas del sistema crearemos, dentro del c&amp;oacute;digo del paquete de nuestro proyecto de integraci&amp;oacute;n, un conjunto de colecciones auxiliares, que contendr&amp;aacute;n, respectivamente, los nombres de las vistas, procedimientos almacenados y funciones de usuario de la base de datos. Posteriormente recorreremos estas colecciones, y por cada uno de sus elementos, accederemos a la colecci&amp;oacute;n-elemento equivalente que existe en la clase Microsoft.SqlServer.Management.Smo.Database, para ejecutar su m&amp;eacute;todo Script, agregando la sentencia de creaci&amp;oacute;n resultante al archivo de script.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Los espacios de nombres System.Data.SqlClient, System.Collections.Specialized y la creaci&amp;oacute;n de colecciones auxiliares&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Accediendo al editor de c&amp;oacute;digo del paquete, comenzaremos a implementar las operaciones que acabamos de describir declarando el espacio de nombres System.Data.SqlClient, mediante el cual tendremos acceso a las clases SqlConnection, SqlCommand y SqlDataReader, necesarias para manipular los objetos de la base de datos con los que deberemos trabajar.&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n nos desplazaremos hasta el bucle foreach que recorre la colecci&amp;oacute;n Databases del objeto Server, y mediante una conexi&amp;oacute;n (objeto SqlConnection) contra la base de datos en curso, ejecutaremos una consulta a trav&amp;eacute;s de un objeto SqlCommand sobre la vista INFORMATION_SCHEMA.VIEWS, que nos devolver&amp;aacute;, en forma de objeto SqlDataReader, el conjunto de resultados con los nombres de las vistas y esquemas de la base de datos. Seguidamente recorreremos este SqlDataReader y a&amp;ntilde;adiremos sus valores a un objeto StringCollection (para usar este tipo de colecci&amp;oacute;n declararemos el espacio de nombres System.Collections.Specialized). Como resultado, obtendremos una colecci&amp;oacute;n con los nombres de las vistas de usuario y esquemas de la base de datos que queremos incluir en el script, evitando de esta manera las vistas del sistema.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;p&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Data.SqlClient;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Collections.Specialized;&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((!oDatabase.IsSystemObject) &amp;amp;&amp;amp; (!oDatabase.Name.StartsWith(&lt;span style="color:#006080;"&gt;&amp;quot;Report&amp;quot;&lt;/span&gt;)))&lt;br /&gt;    {&lt;br /&gt;        Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando BBDD: &amp;quot;&lt;/span&gt; + oDatabase.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#008000;"&gt;// conexi&amp;oacute;n&lt;/span&gt;&lt;br /&gt;        SqlConnection oConnection = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SqlConnection(&lt;span style="color:#006080;"&gt;&amp;quot;Data Source=&amp;quot;&lt;/span&gt; + oServer.Name +&lt;br /&gt;            &lt;span style="color:#006080;"&gt;&amp;quot;;Initial Catalog=&amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;quot;;Integrated Security=True&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;        SqlCommand oCommand = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; SqlCommand();&lt;br /&gt;        oCommand.Connection = oConnection;&lt;br /&gt;        oCommand.CommandType = CommandType.Text;&lt;br /&gt;&lt;br /&gt;        oConnection.Open();&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#008000;"&gt;// vistas&lt;/span&gt;&lt;br /&gt;        oCommand.CommandText = &lt;span style="color:#006080;"&gt;&amp;quot;SELECT TABLE_NAME + &amp;#39; &amp;#39; + TABLE_SCHEMA AS Vista &amp;quot;&lt;/span&gt; +&lt;br /&gt;            &lt;span style="color:#006080;"&gt;&amp;quot;FROM INFORMATION_SCHEMA.VIEWS ORDER BY TABLE_SCHEMA, TABLE_NAME&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;        SqlDataReader oDataReader = oCommand.ExecuteReader();&lt;br /&gt;        StringCollection cllVistas = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; StringCollection();&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;while&lt;/span&gt; (oDataReader.Read())&lt;br /&gt;        {&lt;br /&gt;            cllVistas.Add(oDataReader[&lt;span style="color:#006080;"&gt;&amp;quot;Vista&amp;quot;&lt;/span&gt;].ToString());&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        oDataReader.Close();&lt;br /&gt;&lt;br /&gt;        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;/p&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Con respecto a los procedimientos almacenados y funciones procederemos de igual modo, pero empleando en este caso la vista INFORMATION_SCHEMA.ROUTINES para crear las colecciones auxiliares, como vemos en el siguiente bloque de c&amp;oacute;digo.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;p&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;// procedimientos almacenados&lt;/span&gt;&lt;br /&gt;oCommand.CommandText = &lt;span style="color:#006080;"&gt;&amp;quot;SELECT ROUTINE_NAME + &amp;#39; &amp;#39; + ROUTINE_SCHEMA AS ProcedimientoAlmacenado &amp;quot;&lt;/span&gt; +&lt;br /&gt;    &lt;span style="color:#006080;"&gt;&amp;quot;FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = &amp;#39;PROCEDURE&amp;#39; &amp;quot;&lt;/span&gt; +&lt;br /&gt;    &lt;span style="color:#006080;"&gt;&amp;quot;ORDER BY ROUTINE_SCHEMA, ROUTINE_NAME&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;oDataReader = oCommand.ExecuteReader();&lt;br /&gt;StringCollection cllProcedimientosAlmacenados = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; StringCollection();&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;while&lt;/span&gt; (oDataReader.Read())&lt;br /&gt;{&lt;br /&gt;    cllProcedimientosAlmacenados.Add(oDataReader[&lt;span style="color:#006080;"&gt;&amp;quot;ProcedimientoAlmacenado&amp;quot;&lt;/span&gt;].ToString());&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;oDataReader.Close();&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;// funciones&lt;/span&gt;&lt;br /&gt;oCommand.CommandText = &lt;span style="color:#006080;"&gt;&amp;quot;SELECT ROUTINE_NAME + &amp;#39; &amp;#39; + ROUTINE_SCHEMA AS Funcion &amp;quot;&lt;/span&gt; +&lt;br /&gt;    &lt;span style="color:#006080;"&gt;&amp;quot;FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = &amp;#39;FUNCTION&amp;#39; &amp;quot;&lt;/span&gt; +&lt;br /&gt;    &lt;span style="color:#006080;"&gt;&amp;quot;ORDER BY ROUTINE_SCHEMA, ROUTINE_NAME&amp;quot;&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;oDataReader = oCommand.ExecuteReader();&lt;br /&gt;StringCollection cllFunciones = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; StringCollection();&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;while&lt;/span&gt; (oDataReader.Read())&lt;br /&gt;{&lt;br /&gt;    cllFunciones.Add(oDataReader[&lt;span style="color:#006080;"&gt;&amp;quot;Funcion&amp;quot;&lt;/span&gt;].ToString());&lt;br /&gt;}&lt;br /&gt;oDataReader.Close();&lt;br /&gt;&lt;br /&gt;oConnection.Close();&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;/p&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creaci&amp;oacute;n de las sentencias para el script&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Finalizada la creaci&amp;oacute;n de las colecciones&amp;nbsp;auxiliares, nuestro siguiente paso consistir&amp;aacute; en crear las sentencias de script para la base de datos y tablas; operaciones que no han sufrido modificaci&amp;oacute;n con respecto al anterior art&amp;iacute;culo, ya que en este caso no debemos lidiar con objetos del sistema.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;// base de datos&lt;/span&gt;&lt;br /&gt;oScriptingOptions.FileName = sRutaArchivo + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;quot;.sql&amp;quot;&lt;/span&gt;;&lt;br /&gt;oDatabase.Script(oScriptingOptions);&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;// tablas&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Table oTable &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.Tables)&lt;br /&gt;{&lt;br /&gt;    Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty,&lt;br /&gt;        &lt;span style="color:#006080;"&gt;&amp;quot;Procesando tabla: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + oTable.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oTable.Name,&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;    oTable.Script(oScriptingOptions);&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n crearemos un bucle foreach para recorrer cada una de las colecciones auxiliares, accediendo, en cada iteraci&amp;oacute;n, al elemento de la colecci&amp;oacute;n equivalente perteneciente al objeto Database. Para ello, cada cadena (conteniendo los nombres del objeto y esquema, separados por un car&amp;aacute;cter de espacio) que recuperemos de la colecci&amp;oacute;n auxiliar, ser&amp;aacute; asignada, mediante el m&amp;eacute;todo String.Split, a un array de tipo string con dos elementos. Como separador para el m&amp;eacute;todo Split, utilizaremos un array de tipo char con un car&amp;aacute;cter de espacio en blanco.&lt;/p&gt;
&lt;p&gt;Seguidamente, utilizando los valores del array string, accederemos al elemento de la colecci&amp;oacute;n que corresponda en cada caso (Views, StoredProcedures o UserDefinedFunctions) perteneciente al objeto Database, para ejecutar su m&amp;eacute;todo Script. Adicionalmente, emplearemos la enumeraci&amp;oacute;n ObjetosBD en el &amp;iacute;ndice del array, declarada con &amp;aacute;mbito de la clase ScriptMain, para facilitar la lectura del c&amp;oacute;digo.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;p&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;enum&lt;/span&gt; ObjetosBD : &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;br /&gt;{&lt;br /&gt;    Nombre,&lt;br /&gt;    Esquema&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Main()&lt;br /&gt;{&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((!oDatabase.IsSystemObject) &amp;amp;&amp;amp; (!oDatabase.Name.StartsWith(&lt;span style="color:#006080;"&gt;&amp;quot;Report&amp;quot;&lt;/span&gt;)))&lt;br /&gt;        {&lt;br /&gt;            &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;[] aSeparador = { &lt;span style="color:#006080;"&gt;&amp;#39; &amp;#39;&lt;/span&gt; };&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#008000;"&gt;// vistas&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;[] aVista;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sVista &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; cllVistas)&lt;br /&gt;            {&lt;br /&gt;                aVista = sVista.Split(aSeparador);&lt;br /&gt;                Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty,&lt;br /&gt;                    &lt;span style="color:#006080;"&gt;&amp;quot;Procesando vista: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; +&lt;br /&gt;                    aVista[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Esquema] + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + aVista[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Nombre],&lt;br /&gt;                    &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&amp;nbsp;               ((View)oDatabase.Views[&lt;/p&gt;&lt;/pre&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;                     aVista[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Nombre], &lt;/pre&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;p&gt;                     aVista[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Esquema]]).Script(oScriptingOptions);&lt;br /&gt;            }&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#008000;"&gt;// procedimientos almacenados&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;[] aProcedimientoAlmacenado;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sProcedimientoAlmacenado &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; cllProcedimientosAlmacenados)&lt;br /&gt;            {&lt;br /&gt;                aProcedimientoAlmacenado = sProcedimientoAlmacenado.Split(aSeparador);&lt;br /&gt;                Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty,&lt;br /&gt;                    &lt;span style="color:#006080;"&gt;&amp;quot;Procesando procedimiento almacenado: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; +&lt;br /&gt;                    aProcedimientoAlmacenado[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Esquema] + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + aProcedimientoAlmacenado[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Nombre],&lt;br /&gt;                    &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;                ((StoredProcedure)oDatabase.StoredProcedures[&lt;/p&gt;&lt;/pre&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;                     aProcedimientoAlmacenado[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Nombre], &lt;/pre&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;p&gt;                     aProcedimientoAlmacenado[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Esquema]]).Script(oScriptingOptions);&lt;br /&gt;            }&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#008000;"&gt;// funciones&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;[] aFuncion;&lt;br /&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sFuncion &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; cllFunciones)&lt;br /&gt;            {&lt;br /&gt;                aFuncion = sFuncion.Split(aSeparador);&lt;br /&gt;                Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty,&lt;br /&gt;                    &lt;span style="color:#006080;"&gt;&amp;quot;Procesando funci&amp;oacute;n: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; +&lt;br /&gt;                    aFuncion[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Esquema] + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + aFuncion[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Nombre],&lt;br /&gt;                    &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;                ((UserDefinedFunction)oDatabase.UserDefinedFunctions[&lt;/p&gt;&lt;/pre&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;                     aFuncion[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Nombre], &lt;/pre&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;                     aFuncion[(&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ObjetosBD.Esquema]]).Script(oScriptingOptions);&lt;br /&gt;            }&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Tras a&amp;ntilde;adir el anterior bloque de c&amp;oacute;digo al paquete de integraci&amp;oacute;n, volveremos a ejecutar &amp;eacute;ste, comprobando c&amp;oacute;mo los tiempos de proceso se reducir&amp;aacute;n notablemente.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Ajustar el tama&amp;ntilde;o de la base de datos en la sentencia de creaci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si abrimos cualquiera de los archivos de script generados tras la ejecuci&amp;oacute;n del paquete, observaremos que la sentencia &amp;quot;CREATE DATABASE&amp;quot; asigna, para los archivos de datos y log, el tama&amp;ntilde;o actual de la base de datos.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/OptimizandoCreacionScriptsEstructuraBDSSIS_5F00_03.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/OptimizandoCreacionScriptsEstructuraBDSSIS_5F00_03.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Pero supongamos que algunos de estos archivos de datos y log tienen un tama&amp;ntilde;o considerable, y necesitamos que al ser creada la base de datos correspondiente mediante la ejecuci&amp;oacute;n del script, dicho tama&amp;ntilde;o inicial no sea elevado.&lt;/p&gt;
&lt;p&gt;Por tal motivo, la t&amp;eacute;cnica que proponemos para solucionar este problema consiste en acceder y manipular el contenido del archivo de script mediante los m&amp;eacute;todos de las clases File y String, modificando el tama&amp;ntilde;o inicialmente asignado por uno menor. Para ello, pasaremos el contenido del archivo a una variable de tipo string, dentro de la cual, buscaremos las asignaciones de tama&amp;ntilde;o para la base de datos, reemplaz&amp;aacute;ndolas por los nuevos valores. Finalmente, borraremos el archivo original, creando uno nuevo a partir del contenido modificado existente en la variable string.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;p&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Ajustando tama&amp;ntilde;o inicial de archivos: &amp;quot;&lt;/span&gt; + oDatabase.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sTextoScript = File.ReadAllText(oScriptingOptions.FileName);&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; nPosicionInicio = sTextoScript.IndexOf(&lt;span style="color:#006080;"&gt;&amp;quot;, SIZE&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; nPosicionFin = sTextoScript.IndexOf(&lt;span style="color:#006080;"&gt;&amp;quot;, MAXSIZE&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;sTextoScript = sTextoScript.Replace(sTextoScript.Substring(nPosicionInicio, &lt;/p&gt;&lt;/pre&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;p&gt;(nPosicionFin - nPosicionInicio)), &lt;span style="color:#006080;"&gt;&amp;quot;, SIZE = 3072KB&amp;quot;&lt;/span&gt;);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;nPosicionInicio = sTextoScript.IndexOf(&lt;span style="color:#006080;"&gt;&amp;quot;, SIZE&amp;quot;&lt;/span&gt;, nPosicionInicio + 6);&lt;br /&gt;nPosicionFin = sTextoScript.IndexOf(&lt;span style="color:#006080;"&gt;&amp;quot;, MAXSIZE&amp;quot;&lt;/span&gt;, nPosicionFin + 6);&lt;br /&gt;&lt;br /&gt;sTextoScript = sTextoScript.Replace(sTextoScript.Substring(nPosicionInicio, &lt;/p&gt;&lt;/pre&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;p&gt;(nPosicionFin - nPosicionInicio)), &lt;span style="color:#006080;"&gt;&amp;quot;, SIZE = 1024KB&amp;quot;&lt;/span&gt;);&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;File.Delete(oScriptingOptions.FileName);&lt;br /&gt;&lt;br /&gt;File.WriteAllText(oScriptingOptions.FileName, sTextoScript);&lt;/p&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Realizadas las anteriores modificaciones sobre nuestro c&amp;oacute;digo fuente, damos por concluido este art&amp;iacute;culo, en el que hemos expuesto una t&amp;eacute;cnica para optimizar el tiempo empleado por un paquete de Integration Services en generar los archivos de script conteniendo las estructuras de las bases de datos de SQL Server. Espero que os sirva de ayuda.&lt;/p&gt;
&lt;p&gt;Un saludo.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=201188" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Trucos" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Trucos/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Integration Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Integration+Services/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="SSIS" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SSIS/default.aspx" /></entry><entry><title>Utilizando SSIS para crear scripts de respaldo con la estructura de la base de datos (y 2)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/10/03/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-y-2.aspx" /><id>/blogs/lmblanco/archive/2011/10/03/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-y-2.aspx</id><published>2011-10-03T19:02:00Z</published><updated>2011-10-03T19:02:00Z</updated><content type="html">&lt;p&gt;En la &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/10/02/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-1.aspx"&gt;primera entrega&lt;/a&gt; de este art&amp;iacute;culo realiz&amp;aacute;bamos una introducci&amp;oacute;n al desarrollo de proyectos de Integration Services desde el entorno de BIDS, con el objetivo de crear scripts de la estructura de las bases de datos de nuestro servidor utilizando Script Task, un componente de los paquetes de integraci&amp;oacute;n. Ser&amp;aacute; en esta segunda parte, cuando nos centraremos en la generaci&amp;oacute;n de los mencionados archivos de script.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;La clase ScriptingOptions, el m&amp;eacute;todo Script y la generaci&amp;oacute;n del archivo de script&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Pasemos a la siguiente fase en el desarrollo de nuestro proceso (el proyecto de Integration Services con los ejemplos puede descargarse &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201110/EstructurasBBDDzip.txt"&gt;aqu&amp;iacute;&lt;/a&gt;), que consistir&amp;aacute; en crear un archivo de script, que de momento solamente incluir&amp;aacute; las sentencias de creaci&amp;oacute;n de la base de datos. Esta operaci&amp;oacute;n ser&amp;aacute; realizada dentro del bucle que recorre la colecci&amp;oacute;n de bases de datos del servidor, obteniendo un archivo por cada base de datos. Previamente deberemos crear la carpeta &amp;quot;C:\EstructurasBBDDCopias&amp;quot;, que ser&amp;aacute; donde se generen los archivos.&lt;/p&gt;
&lt;p&gt;La manera de especificar el archivo de script pasa por utilizar un objeto de la clase ScriptingOptions, que como adivinamos por su nombre, es la encargada de configurar las opciones relativas a la generaci&amp;oacute;n del archivo. Una vez instanciado dicho objeto, la propiedad FileName ser&amp;aacute; la que utilicemos para indicar el nombre y ruta del archivo que se va a crear; mientras que el acto de generaci&amp;oacute;n lo llevaremos a cabo llamando al m&amp;eacute;todo Server.Script, pas&amp;aacute;ndole como par&amp;aacute;metro el objeto ScriptingOptions.&lt;/p&gt;
&lt;p&gt;Dado que este es un proceso que probablemente ejecutaremos con cierta frecuencia, a&amp;ntilde;adiremos las instrucciones necesarias para crear, dentro de la carpeta &amp;quot;C:\EstructurasBBDDCopias&amp;quot;, una subcarpeta cuyo nombre sea la fecha de ejecuci&amp;oacute;n del paquete, siendo esta &amp;uacute;ltima, la carpeta en donde se depositar&amp;aacute;n los archivos de script. Para poder utilizar los objetos necesarios para la manipulaci&amp;oacute;n de carpetas, a&amp;ntilde;adiremos a nuestro c&amp;oacute;digo la declaraci&amp;oacute;n del espacio de nombres System.IO.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.IO;&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;Server oServer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Server(&lt;span style="color:#006080;"&gt;&amp;quot;WINTERFELL-PC&amp;quot;&lt;/span&gt;);&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; bOtraVez = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sRutaArchivo = &lt;span style="color:#006080;"&gt;@&amp;quot;C:\EstructurasBBDDCopias\&amp;quot; + DateTime.Today.ToString(&amp;quot;&lt;/span&gt;yyyyMMdd&lt;span style="color:#006080;"&gt;&amp;quot;) + @&amp;quot;\&amp;quot;&lt;/span&gt;;&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (Directory.Exists(sRutaArchivo))&lt;br /&gt;{&lt;br /&gt;    Directory.Delete(sRutaArchivo, &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;);&lt;br /&gt;}&lt;br /&gt;
&lt;br /&gt;Directory.CreateDirectory(sRutaArchivo);&lt;br /&gt;
&lt;br /&gt;ScriptingOptions oScriptingOptions = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ScriptingOptions();&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;{&lt;br /&gt;    Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando BBDD: &amp;quot;&lt;/span&gt; + oDatabase.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;    oScriptingOptions.FileName = sRutaArchivo + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;quot;.sql&amp;quot;&lt;/span&gt;;&lt;br /&gt;    oDatabase.Script(oScriptingOptions);&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Despu&amp;eacute;s de ejecutar nuevamente el paquete, en la ruta especificada aparecer&amp;aacute;n los archivos reci&amp;eacute;n creados, en cuyo interior encontraremos las sentencias de creaci&amp;oacute;n de la base de datos.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_17.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DATABASE&lt;/span&gt; [Chinook]&lt;br /&gt; CONTAINMENT = &lt;span style="color:#0000ff;"&gt;NONE&lt;/span&gt;&lt;br /&gt; &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt;  &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;br /&gt;( NAME = N&lt;span style="color:#006080;"&gt;&amp;#39;Chinook&amp;#39;&lt;/span&gt;, FILENAME = N&lt;span style="color:#006080;"&gt;&amp;#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Chinook.mdf&amp;#39;&lt;/span&gt; , &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SIZE&lt;/span&gt; = 5184KB , MAXSIZE = UNLIMITED, FILEGROWTH = 1024KB )&lt;br /&gt; LOG &lt;span style="color:#0000ff;"&gt;ON&lt;/span&gt; &lt;br /&gt;( NAME = N&lt;span style="color:#006080;"&gt;&amp;#39;Chinook_log&amp;#39;&lt;/span&gt;, FILENAME = N&lt;span style="color:#006080;"&gt;&amp;#39;C:\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\Chinook_log.ldf&amp;#39;&lt;/span&gt; , &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SIZE&lt;/span&gt; = 1040KB , MAXSIZE = 2048GB , FILEGROWTH = 10%)&lt;br /&gt; &lt;span style="color:#0000ff;"&gt;COLLATE&lt;/span&gt; Modern_Spanish_CI_AS&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;ALTER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DATABASE&lt;/span&gt; [Chinook] &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; COMPATIBILITY_LEVEL = 110&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;--....&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Con toda seguridad habremos observado que se han generado archivos tanto para las bases de datos de usuario como de sistema, aunque probablemente en estas &amp;uacute;ltimas no estemos interesados. Si este es el caso, podemos evitar su creaci&amp;oacute;n interrogando a la propiedad Database.IsSystemObject, de tipo bool, mediante la que averiguaremos si se trata de una base de datos de sistema o usuario.&lt;/p&gt;
&lt;p&gt;Con las bases de datos del servidor de informes estamos en una situaci&amp;oacute;n parecida, pero como se trata de bases de datos de usuario, si no queremos generar script para ellas lo haremos comprobando el comienzo de su nombre.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((!oDatabase.IsSystemObject) &amp;amp;&amp;amp; (!oDatabase.Name.StartsWith(&lt;span style="color:#006080;"&gt;&amp;quot;Report&amp;quot;&lt;/span&gt;)))&lt;br /&gt;    {&lt;br /&gt;        Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando BBDD: &amp;quot;&lt;/span&gt; + oDatabase.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;        oScriptingOptions.FileName = sRutaArchivo + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;quot;.sql&amp;quot;&lt;/span&gt;;&lt;br /&gt;        oDatabase.Script(oScriptingOptions);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;&lt;b&gt;Modificaci&amp;oacute;n de valores a trav&amp;eacute;s de variables&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para especificar el nombre del servidor con el que trabajamos y la ruta en la que se crear&amp;aacute;n los archivos, actualmente utilizamos valores fijos de cadena, lo cual se convertir&amp;aacute; en un inconveniente cuando tengamos que instalar el paquete en un servidor distinto del utilizado para el desarrollo, o bien queramos emplear una ruta diferente para la creaci&amp;oacute;n de los scripts.&lt;/p&gt;
&lt;p&gt;Podemos remediar este problema gracias a la posibilidad de declarar variables en el dise&amp;ntilde;ador del paquete, cuyos valores pueden ser recuperados desde el c&amp;oacute;digo fuente en el momento de su ejecuci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Para declarar una variable nos situaremos en la ventana &amp;quot;Variables&amp;quot; de Visual Studio y haremos clic en el bot&amp;oacute;n &amp;quot;Add Variable&amp;quot; de su barra de herramientas, cre&amp;aacute;ndose la nueva variable vac&amp;iacute;a, cuyos campos de propiedad (Name, Data type y Value) completaremos con los valores oportunos. En la siguiente imagen vemos la creaci&amp;oacute;n de la variable RutaArchivos, de tipo cadena, con el valor &amp;quot;C:\EstructurasBBDDCopias\&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_18.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En el caso de que esta ventana est&amp;eacute; oculta, la mostraremos seleccionando la opci&amp;oacute;n de men&amp;uacute; de Visual Studio &amp;quot;SSIS | Variables&amp;quot;.&lt;/p&gt;
&lt;p&gt;Adem&amp;aacute;s de las variables creadas por el desarrollador, disponemos tambi&amp;eacute;n de un conjunto de variables de sistema, que podemos visualizar haciendo clic en el bot&amp;oacute;n &amp;quot;Show System Variables&amp;quot; de la barra herramientas de esta misma ventana. Para el ejemplo que estamos desarrollando, haremos uso de la variable &amp;quot;MachineName&amp;quot;, que nos proporcionar&amp;aacute; el nombre del servidor en el que se ejecuta el paquete.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_19.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El siguiente paso consistir&amp;aacute; en preparar las variables para que puedan estar accesibles desde el c&amp;oacute;digo fuente del paquete. Para ello, abriremos la ventana &amp;quot;Script Task Editor&amp;quot; del objeto Script Task, y en la propiedad &amp;quot;ReadOnlyVariables&amp;quot;, perteneciente a la categor&amp;iacute;a &amp;quot;Script&amp;quot;, escribiremos los nombres de las variables como una lista separada por comas, o bien haremos clic en el bot&amp;oacute;n de puntos suspensivos, que abrir&amp;aacute; la ventana &amp;quot;Select Variables&amp;quot;, en donde realizaremos la selecci&amp;oacute;n, lo que tendr&amp;aacute; el mismo efecto.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_20.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n volveremos a la ventana del editor de c&amp;oacute;digo, donde para recuperar&amp;nbsp;el valor de las variables emplearemos la colecci&amp;oacute;n &amp;quot;Variables&amp;quot; del objeto Dts, situando en el &amp;iacute;ndice de la colecci&amp;oacute;n una cadena con el nombre de la variable a obtener, como vemos en el siguiente bloque de c&amp;oacute;digo.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;Server oServer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Server(Dts.Variables[&lt;span style="color:#006080;"&gt;&amp;quot;System::MachineName&amp;quot;&lt;/span&gt;].Value.ToString());&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; bOtraVez = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sRutaArchivo = Dts.Variables[&lt;span style="color:#006080;"&gt;&amp;quot;User::RutaArchivos&amp;quot;&lt;/span&gt;].Value.ToString() + DateTime.Today.ToString(&lt;span style="color:#006080;"&gt;&amp;quot;yyyyMMdd&amp;quot;&lt;/span&gt;) + @&amp;quot;\&amp;quot;;&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Para pasar valores a las variables del paquete, una vez &amp;eacute;ste ha sido importado al servidor de Integration Services, podemos utilizar la ventana &amp;quot;Execute Package Utility&amp;quot;. En la categor&amp;iacute;a &amp;quot;Command Line&amp;quot; haremos clic en el RadioButton &amp;quot;Edit the command line manually&amp;quot;, a&amp;ntilde;adiendo al final de las opciones del comando DTExec la siguiente opci&amp;oacute;n /SET, con la que cambiaremos la ruta en donde se crear&amp;aacute;n los scripts.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;/SET &amp;quot;\Package.Variables[User::RutaArchivos].Value&amp;quot;;&amp;quot;C:\Pruebas\\&amp;quot;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_21.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Estos mismos valores ser&amp;aacute;n los que usaremos en el caso de ejecutar el paquete desde la l&amp;iacute;nea de comandos en&amp;nbsp;una ventana &amp;quot;S&amp;iacute;mbolo del sistema&amp;quot; mediante la utilidad DTExec.exe.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_22.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Incorporando las tablas al proceso&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Los siguientes objetos que vamos a generar en el script ser&amp;aacute;n las tablas, por lo que siguiendo la misma mec&amp;aacute;nica utilizada con las bases de datos, crearemos un bucle que recorrer&amp;aacute; la colecci&amp;oacute;n Tables del objeto Database en el que estemos posicionados, a&amp;ntilde;adiendo cada tabla al archivo por medio de su m&amp;eacute;todo Script.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;p&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((!oDatabase.IsSystemObject) &amp;amp;&amp;amp; (!oDatabase.Name.StartsWith(&lt;span style="color:#006080;"&gt;&amp;quot;Report&amp;quot;&lt;/span&gt;)))&lt;br /&gt;    {&lt;br /&gt;        Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando BBDD: &amp;quot;&lt;/span&gt; + oDatabase.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;        oScriptingOptions.FileName = sRutaArchivo + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;quot;.sql&amp;quot;&lt;/span&gt;;&lt;br /&gt;        oDatabase.Script(oScriptingOptions);&lt;/p&gt;&lt;p&gt;
&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Table oTable &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.Tables)&lt;br /&gt;        {&lt;br /&gt;            Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando tabla: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + &lt;br /&gt;                oTable.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oTable.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;            oTable.Script(oScriptingOptions);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;/p&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Al ejecutar el paquete los archivos ser&amp;aacute;n generados de nuevo, pero si abrimos cualquiera de ellos nos llevaremos una desagradable sorpresa, ya que s&amp;oacute;lo contendr&amp;aacute;n una &amp;uacute;nica sentencia de creaci&amp;oacute;n de tabla. Esto es debido a que, por defecto, el m&amp;eacute;todo Script, cada vez que es llamado, sobrescribe el contenido del archivo con la sentencia reci&amp;eacute;n generada.&lt;/p&gt;
&lt;p&gt;Igualmente nos encontraremos ante otra serie de inconvenientes como son la ausencia de las sentencias para la creaci&amp;oacute;n de los &amp;iacute;ndices de las tablas, claves primarias, externas, etc.&lt;/p&gt;
&lt;p&gt;Para evitar este comportamiento recurriremos nuevamente al objeto ScriptingOptions, asignando el valor true a las propiedades que describimos a continuaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;--AppendToFile. Las sentencias generadas mediante el m&amp;eacute;todo Script se ir&amp;aacute;n agregando al archivo sobre el que estamos trabajando, evitando as&amp;iacute; que la &amp;uacute;ltima sentencia reemplace su contenido.&lt;/p&gt;
&lt;p&gt;--IncludeDatabaseContext. Antes de cada sentencia de creaci&amp;oacute;n de tabla se crear&amp;aacute; una sentencia &amp;quot;USE NombreBBDD&amp;quot;, que nos asegure que la tabla sea creada en la base de datos correcta.&lt;/p&gt;
&lt;p&gt;--Indexes. A&amp;ntilde;ade las sentencias para la creaci&amp;oacute;n de &amp;iacute;ndices (agrupados / no agrupados) y claves primarias en las tablas.&lt;/p&gt;
&lt;p&gt;--DriForeignKeys. A&amp;ntilde;ade las sentencias para la creaci&amp;oacute;n de las claves externas de las tablas.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;ScriptingOptions oScriptingOptions = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ScriptingOptions();&lt;br /&gt;oScriptingOptions.AppendToFile = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;oScriptingOptions.IncludeDatabaseContext = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;oScriptingOptions.Indexes = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;oScriptingOptions.DriForeignKeys = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Dentro del apartado de creaci&amp;oacute;n de &amp;iacute;ndices, gracias a las propiedades DriPrimaryKey, ClusteredIndexes y NonClusteredIndexes, pertenecientes a la clase ScriptingOptions, vamos a tener la capacidad de ser m&amp;aacute;s selectivos a la hora de elegir el tipo de &amp;iacute;ndice a incluir en el script. Si por ejemplo, en el script solamente queremos a&amp;ntilde;adir sentencias para crear los &amp;iacute;ndices agrupados y las claves primarias, dejando fuera los &amp;iacute;ndices no agrupados, en primer lugar asignaremos false a la propiedad Indexes, para impedir as&amp;iacute; la creaci&amp;oacute;n de todos los tipos de &amp;iacute;ndices, y despu&amp;eacute;s realizaremos la asignaci&amp;oacute;n de las propiedades antes mencionadas, para que sean creados los tipos de &amp;iacute;ndices elegidos.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;oScriptingOptions.Indexes = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;&lt;br /&gt;oScriptingOptions.DriPrimaryKey = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;oScriptingOptions.ClusteredIndexes = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;&lt;br /&gt;oScriptingOptions.NonClusteredIndexes = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Vistas, procedimientos almacenados, funciones y objetos del sistema&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;La inclusi&amp;oacute;n en el proceso de otros objetos de la base de datos tales como vistas, procedimientos almacenados, funciones, etc., no reviste mayor complicaci&amp;oacute;n que la de a&amp;ntilde;adir un nuevo bucle foreach, que recorra la colecci&amp;oacute;n correspondiente del objeto Database: Views, StoredProcedures, UserDefinedFunctions, etc.&lt;/p&gt;
&lt;p&gt;Entre los tipos de objetos que acabamos de mencionar, adem&amp;aacute;s de los creados por el usuario, existen versiones del sistema, y adicionalmente, algunos de estos procedimientos almacenados y funciones del sistema se encuentran encriptados (los reconoceremos&amp;nbsp;en SQL Server Management Studio&amp;nbsp;porque su icono muestra un candado), provocando un error si intentamos incluirlos en el script. Es por ello que debemos evitar esta situaci&amp;oacute;n, consultando su propiedad IsEncypted, como vemos en el siguiente bloque de c&amp;oacute;digo.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_23.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((!oDatabase.IsSystemObject) &amp;amp;&amp;amp; (!oDatabase.Name.StartsWith(&lt;span style="color:#006080;"&gt;&amp;quot;Report&amp;quot;&lt;/span&gt;)))&lt;br /&gt;{&lt;br /&gt;    &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (View oView &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.Views)&lt;br /&gt;    {&lt;br /&gt;        Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando vista: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oView.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oView.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;        oView.Script(oScriptingOptions);&lt;br /&gt;        }&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (StoredProcedure oStoredProcedure &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.StoredProcedures)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (!oStoredProcedure.IsEncrypted)&lt;br /&gt;        {&lt;br /&gt;            Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando procedimiento almacenado: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oStoredProcedure.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oStoredProcedure.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;            oStoredProcedure.Script(oScriptingOptions);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (UserDefinedFunction oUserDefinedFunction &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.UserDefinedFunctions)&lt;br /&gt;    {&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (!oUserDefinedFunction.IsEncrypted)&lt;br /&gt;        {&lt;br /&gt;            Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando funci&amp;oacute;n: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oUserDefinedFunction.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oUserDefinedFunction.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;            oUserDefinedFunction.Script(oScriptingOptions);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Por otra parte, la inclusi&amp;oacute;n de estos objetos del sistema har&amp;aacute; que el archivo de script crezca hasta alcanzar un tama&amp;ntilde;o considerable, por lo que es posible que no deseemos a&amp;ntilde;adirlos.&lt;/p&gt;
&lt;p&gt;Si este es nuestro caso, el modo m&amp;aacute;s sencillo de resolver el problema consiste en asignar false a la propiedad ScriptingOptions.AllowSystemObjects. De esta forma tampoco ser&amp;iacute;a necesario comprobar si ciertos objetos est&amp;aacute;n encriptados, obteniendo adem&amp;aacute;s un archivo de script con un tama&amp;ntilde;o m&amp;aacute;s reducido.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;ScriptingOptions oScriptingOptions = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ScriptingOptions();&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;oScriptingOptions.AllowSystemObjects = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (View oView &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.Views)&lt;br /&gt;{&lt;br /&gt;    Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando vista: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oView.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oView.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;    oView.Script(oScriptingOptions);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;pre style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (StoredProcedure oStoredProcedure &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.StoredProcedures)&lt;br /&gt;{&lt;br /&gt;    Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando procedimiento almacenado: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oStoredProcedure.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oStoredProcedure.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;    oStoredProcedure.Script(oScriptingOptions);&lt;br /&gt;}&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (UserDefinedFunction oUserDefinedFunction &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDatabase.UserDefinedFunctions)&lt;br /&gt;{&lt;br /&gt;    Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando funci&amp;oacute;n: &amp;quot;&lt;/span&gt; + oDatabase.Name + &lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt; + &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; oUserDefinedFunction.Schema + &lt;span style="color:#006080;"&gt;&amp;#39;.&amp;#39;&lt;/span&gt; + oUserDefinedFunction.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;    oUserDefinedFunction.Script(oScriptingOptions);&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Sin embargo, el hecho de no a&amp;ntilde;adir los objetos del sistema al script no va a suponer una mejora significativa en la duraci&amp;oacute;n del proceso, ya que a pesar de que el valor de la propiedad AllowSystemObjects sea false, las colecciones Views, StoredProcedures y UserDefinedFunctions siguen conteniendo los objetos del sistema.&lt;/p&gt;
&lt;p&gt;Con el fin de agilizar estos tiempos de ejecuci&amp;oacute;n, las colecciones que utilizamos para construir el script deber&amp;iacute;an contener &amp;uacute;nica y exclusivamente aquellos objetos que vayamos a incluir en el archivo. No obstante, esta es una tarea de optimizaci&amp;oacute;n que queda fuera del &amp;aacute;mbito del presente art&amp;iacute;culo, pero que abordaremos pr&amp;oacute;ximamente. Por el momento, confiamos en que la soluci&amp;oacute;n aqu&amp;iacute; propuesta&amp;nbsp; resulte de utilidad para todos aquellos lectores que precisen crear scripts con las estructuras de sus bases de datos.&lt;/p&gt;
&lt;p&gt;Un saludo.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=200967" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Integration Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Integration+Services/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="SSIS" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SSIS/default.aspx" /></entry><entry><title>Utilizando SSIS para crear scripts de respaldo con la estructura de la base de datos (1)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/10/02/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-1.aspx" /><id>/blogs/lmblanco/archive/2011/10/02/utilizando-ssis-para-crear-scripts-de-respaldo-con-la-estructura-de-la-base-de-datos-1.aspx</id><published>2011-10-02T14:53:00Z</published><updated>2011-10-02T14:53:00Z</updated><content type="html">&lt;p&gt;Dentro del contexto de cualquier sistema de informaci&amp;oacute;n, resulta fundamental la existencia de una adecuada pol&amp;iacute;tica de copia de seguridad, como medio de contar con un respaldo para proteger los datos almacenados.&lt;/p&gt;
&lt;p&gt;Si nos ce&amp;ntilde;imos, sin embargo, al desarrollo de sistemas Business Intelligence, con cierta frecuencia podemos encontrarnos ante un almac&amp;eacute;n de datos en el que cada vez que debamos procesar los cubos y dimensiones que lo integran, primeramente habremos de vaciar las tablas asociadas a dichos elementos, para recargarlas por completo con datos actualizados provenientes de muy diversas fuentes.&lt;/p&gt;
&lt;p&gt;En un escenario como el que presentamos, antes que la salvaguardia de los datos resulta m&amp;aacute;s importante hacer una copia de la estructura de las tablas, vistas, procedimientos almacenados, etc., de la base de datos, m&amp;aacute;xime si se trata de un almac&amp;eacute;n de datos que se encuentra en pleno proceso de desarrollo, ya que la informaci&amp;oacute;n reside en las fuentes de datos originales que se usan para realizar la carga del almac&amp;eacute;n, las cuales, habitualmente, disponen de sus propios mecanismos de copia de seguridad.&lt;/p&gt;
&lt;p&gt;Por dicho motivo, en el presente art&amp;iacute;culo vamos a centrarnos en desarrollar un proceso que se ocupe de generar, para cada una de las bases de datos de nuestra instancia de SQL Server, un archivo de script con todas las instrucciones de definici&amp;oacute;n (Data Definition Language) de los objetos integrantes de la base de datos. Para lograrlo emplearemos paquetes de SSIS (SQL Server Integration Services), y m&amp;aacute;s concretamente, el componente &amp;quot;Script Task&amp;quot;, que nos otorgar&amp;aacute; un alto grado de flexibilidad y control sobre la generaci&amp;oacute;n de los archivos de script y los objetos de la base de datos a incluir en dichos archivos.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Scptxfr.exe. Los or&amp;iacute;genes en SQL Server 2000&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Pero antes de adentrarnos en el desarrollo del proceso en SSIS, queremos hacer menci&amp;oacute;n a scptxfr.exe, una herramienta que puede resultar de utilidad para aquellos lectores que todav&amp;iacute;a tengan que realizar el mantenimiento de sistemas basados en SQL Server 2000.&lt;/p&gt;
&lt;p&gt;Ejecutada en modo l&amp;iacute;nea de comando&amp;nbsp;desde una ventana &amp;quot;S&amp;iacute;mbolo del sistema&amp;quot;, o bien desde un procedimiento almacenado, tambi&amp;eacute;n nos permite, aunque con menos flexibilidad que en SSIS, como veremos m&amp;aacute;s adelante, generar un conjunto de archivos con las instrucciones de creaci&amp;oacute;n de tablas, &amp;iacute;ndices, claves primarias, vistas, etc., necesarios para la adecuada regeneraci&amp;oacute;n de una base de datos.&lt;/p&gt;
&lt;p&gt;Entre los par&amp;aacute;metros de que dispone, destacaremos los siguientes:&lt;/p&gt;
&lt;p&gt;-- /s. Nombre del servidor SQL Server con el que vamos a trabajar.&lt;/p&gt;
&lt;p&gt;-- /d. Nombre de la base de datos a partir de la que vamos a generar los scripts.&lt;/p&gt;
&lt;p&gt;-- /I. Tipo de autenticaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;-- /F. Nombre (incluyendo ruta si es preciso) del archivo script destino.&lt;/p&gt;
&lt;p&gt;Para una descripci&amp;oacute;n m&amp;aacute;s detallada de todos los par&amp;aacute;metros, sugerimos al lector que ejecute la instrucci&amp;oacute;n SCPTXFR /? desde una ventana de s&amp;iacute;mbolo del sistema.&lt;/p&gt;
&lt;p&gt;De esta forma podr&amp;iacute;amos crear un procedimiento almacenado como el que vemos a continuaci&amp;oacute;n, que recorriera las bases de datos del servidor SQL Server, y creara, por cada una de ellas, una carpeta con los archivos de script correspondientes.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;PROCEDURE&lt;/span&gt; CrearEstructurasDB&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; #NombresDBs&lt;br /&gt;(&lt;br /&gt;Linea_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;identity&lt;/span&gt;(1,1), &lt;br /&gt;Nombre &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(150)&lt;br /&gt;)&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;INSERT INTO&lt;/span&gt; #NombresDBs&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; name &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; master..sysdatabases &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt; name

&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @sDirectorioBak &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(50)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @sDirectorioBak = &lt;span style="color:#006080;"&gt;&amp;#39;c:\pruebas\&amp;#39;&lt;/span&gt; + &lt;span style="color:#0000ff;"&gt;convert&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;,getdate(),112) + &lt;span style="color:#006080;"&gt;&amp;#39;\&amp;#39;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nLineaID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @nLineaID = 1&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nLineaIDUltimo &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @nLineaIDUltimo = (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;MAX&lt;/span&gt;(Linea_ID) &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; #NombresDBs)&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @sCmdCrearDirectorio &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(200)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @sNombreDB &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(150)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @sCmd &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(300)&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WHILE&lt;/span&gt; (@nLineaID &amp;lt;= @nLineaIDUltimo)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @sNombreDB = Nombre &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; #NombresDBs &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; Linea_ID = @nLineaID&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @sCmdCrearDirectorio = &lt;span style="color:#006080;"&gt;&amp;#39;MKDIR&amp;#39;&lt;/span&gt; + @sDirectorioBak + @sNombreDB&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;EXECUTE&lt;/span&gt; master..xp_cmdshell @sCmdCrearDirectorio&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @sCmd = &lt;span style="color:#006080;"&gt;&amp;#39;&amp;quot;&amp;#39;&lt;/span&gt; + &lt;span style="color:#006080;"&gt;&amp;#39;C:\Archivos de programa\Microsoft SQL Server\MSSQL\Upgrade\scptxfr&amp;#39;&lt;/span&gt; + &lt;span style="color:#006080;"&gt;&amp;#39;&amp;quot; /s &amp;#39;&lt;/span&gt; +&lt;br /&gt;        &lt;span style="color:#cc6633;"&gt;@@servername&lt;/span&gt; + &lt;span style="color:#006080;"&gt;&amp;#39; /d &amp;#39;&lt;/span&gt; + @sNombreDB + &lt;span style="color:#006080;"&gt;&amp;#39; /I /F &amp;#39;&lt;/span&gt; + @sDirectorioBak + @sNombreDB&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;EXECUTE&lt;/span&gt; master..xp_cmdshell @sCmd&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @nLineaID = @nLineaID + 1&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;end&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DROP&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; #NombresDBs&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Dado que el anterior procedimiento almacenado crea los archivos de script en una ruta cuyo nombre incluye la fecha del sistema, podemos programar su ejecuci&amp;oacute;n dentro de una tarea de SQL Server, y obtener de esa forma una copia de respaldo diaria o con la frecuencia que establezcamos, de los scripts de creaci&amp;oacute;n de las bases de datos.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;SSIS y los paquetes de integraci&amp;oacute;n. La evoluci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Pero seg&amp;uacute;n reza su t&amp;iacute;tulo, nos encontramos ante un art&amp;iacute;culo basado en SSIS, por lo que tendremos que usar SQL Server 2005 o superior, ya que es a partir de dicha versi&amp;oacute;n cuando se incluy&amp;oacute; esta tecnolog&amp;iacute;a de integraci&amp;oacute;n de datos.&lt;/p&gt;
&lt;p&gt;Utilizaremos por lo tanto &lt;a href="https://www.microsoft.com/betaexperience/pd/SQLDCTP3CTA/enus/"&gt;SQL Server Denali CTP3&lt;/a&gt;, dado que se trata de la versi&amp;oacute;n m&amp;aacute;s reciente disponible de SQL Server en el momento de desarrollar los ejemplos del art&amp;iacute;culo. Para generar los scripts de estructuras emplearemos las bases de datos &lt;a href="http://msftdbprodsamples.codeplex.com/releases/view/55330"&gt;AdventureWorks2008R2&lt;/a&gt; y &lt;a href="http://chinookdatabase.codeplex.com/releases/view/21111"&gt;Chinook&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;El proyecto de servicios de integraci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En primer lugar iniciaremos &amp;quot;SQL Server Business Intelligence Development Studio&amp;quot; (SSBIDS), o lo que es lo mismo, el entorno&amp;nbsp; de desarrollo de Visual Studio 2010, situado en la ruta de men&amp;uacute; &amp;quot;Inicio |Microsoft SQL Server Denali CTP3&amp;quot;.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_01.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esta versi&amp;oacute;n especial de Visual Studio 2010, que acompa&amp;ntilde;a a SQL Server, contiene las plantillas espec&amp;iacute;ficas para la creaci&amp;oacute;n de proyectos de inteligencia de negocio. Por lo que seleccionando la opci&amp;oacute;n de men&amp;uacute; &amp;quot;File | New | Project&amp;quot;, abriremos el di&amp;aacute;logo &amp;quot;New Project&amp;quot;, donde elegiremos un proyecto de tipo &amp;quot;Integration Services Project&amp;quot; al que daremos el nombre EstructurasBBDD.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_02.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Este tipo de proyecto incluye por defecto un paquete llamado Package.dtsx, al que cambiaremos el nombre por PckEstructurasBBDD.dtsx, utilizando la propiedad &amp;quot;File Name&amp;quot; de la ventana de propiedades. Tambi&amp;eacute;n podemos hacer clic derecho en el paquete y elegir la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Rename&amp;quot;.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_03.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Script Task. Desarrollo program&amp;aacute;tico de operaciones personalizadas &amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Una vez abierto el paquete, el siguiente paso consistir&amp;aacute; en a&amp;ntilde;adir al dise&amp;ntilde;ador una tarea de c&amp;oacute;digo fuente haciendo doble clic en el icono &amp;quot;Script Task&amp;quot;, situado en la ventana &amp;quot;SSIS Toolbox&amp;quot; del entorno de desarrollo.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_04.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Tambi&amp;eacute;n cambiaremos el nombre predeterminado de este elemento por scptEstructurasBBDD editando su propiedad Name.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_05.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Escritura y ejecuci&amp;oacute;n del c&amp;oacute;digo de Script Task&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para escribir el c&amp;oacute;digo de nuestras operaciones haremos clic derecho sobre el objeto Script Task, y elegiremos la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Edit&amp;quot;, que abrir&amp;aacute; el di&amp;aacute;logo &amp;quot;Script Task Editor&amp;quot;. De las diversas propiedades disponibles, ScriptLanguage, ubicada dentro de la categor&amp;iacute;a &amp;quot;Script&amp;quot;, nos permite establecer el lenguaje que vamos a usar para programar el proceso (por defecto es C#, aunque tambi&amp;eacute;n podemos utilizar Visual Basic). Haciendo clic en el bot&amp;oacute;n &amp;quot;Edit Script&amp;quot; abriremos el editor de c&amp;oacute;digo de Visual Studio 2010, ventana que nos resultar&amp;aacute; familiar si hemos trabajado anteriormente con este entorno de desarrollo.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_06.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El punto de entrada en la ejecuci&amp;oacute;n del paquete lo representa el m&amp;eacute;todo Main de la clase ScriptMain, que viene integrada por defecto en el c&amp;oacute;digo del paquete. En este m&amp;eacute;todo escribiremos el c&amp;oacute;digo con aquellas operaciones necesarias para interactuar con los objetos de las bases de datos de la instancia de SQL Server con la que vayamos a trabajar.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_07.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para familiarizarnos con el modelo de objetos a manejar y facilitar as&amp;iacute; el aprendizaje del proceso, vamos a comenzar implementando una operaci&amp;oacute;n muy sencilla: recorrer las bases de datos del servidor y visualizar su nombre.&lt;/p&gt;
&lt;p&gt;En primer lugar necesitamos tener acceso a las clases que representan los objetos del servidor SQL, por lo que debemos a&amp;ntilde;adir las siguientes referencias al paquete:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;--Microsoft.SqlServer.ConnectionInfo&lt;/p&gt;
&lt;p&gt;--Microsoft.SqlServer.Management.Sdk.Sfc&lt;/p&gt;
&lt;p&gt;--Microsoft.SqlServer.Smo&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Haciendo clic derecho sobre el nodo &amp;quot;References&amp;quot; de la ventana &amp;quot;Solution Explorer&amp;quot; elegiremos la opci&amp;oacute;n &amp;quot;Add Reference&amp;quot;, que abrir&amp;aacute; un di&amp;aacute;logo con el mismo nombre desde cuya pesta&amp;ntilde;a &amp;quot;.NET&amp;quot; realizaremos la selecci&amp;oacute;n y agregaci&amp;oacute;n de componentes al paquete.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_08.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n escribiremos el siguiente bloque de c&amp;oacute;digo, que crear&amp;aacute; una instancia de la clase Microsoft.SqlServer.Management.Smo.Server (que representa al servidor SQL), pasando como par&amp;aacute;metros a su constructor una cadena con el nombre del servidor. Utilizando dicho objeto Server, recorreremos su colecci&amp;oacute;n Databases, visualizando el nombre de cada una mediante una ventana MessageBox.&amp;nbsp;&lt;/p&gt;
&lt;div id="Div1"&gt;
&lt;pre id="Pre1" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Data;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; Microsoft.SqlServer.Dts.Runtime;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Windows.Forms;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; Microsoft.SqlServer.Management.Smo;&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Main()&lt;br /&gt;{&lt;br /&gt;    Server oServer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Server(&lt;span style="color:#006080;"&gt;&amp;quot;WINTERFELL-PC&amp;quot;&lt;/span&gt;);&lt;br /&gt;
&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;    {&lt;br /&gt;        MessageBox.Show(oDatabase.Name);&lt;br /&gt;    }&lt;br /&gt;
&lt;br /&gt;    Dts.TaskResult = (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)ScriptResults.Success;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Seguidamente cerraremos el editor de c&amp;oacute;digo y aceptaremos el di&amp;aacute;logo &amp;quot;Script Task Editor&amp;quot;, poniendo en ejecuci&amp;oacute;n el paquete mediante la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Debug | Start debugging&amp;quot; o pulsando la tecla F5, que ir&amp;aacute; mostrando los mensajes correspondientes con los nombres de las bases de datos.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_09.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Finalizada la ejecuci&amp;oacute;n, haremos clic en el enlace &amp;quot;Package execution completed...&amp;quot; que aparece en la parte inferior del dise&amp;ntilde;ador del paquete, o seleccionaremos la opci&amp;oacute;n de men&amp;uacute; &amp;quot;Debug | Stop Debugging&amp;quot; para salir de la ejecuci&amp;oacute;n desde el depurador.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_10.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;No obstante, a pesar de resultar factible, no consideramos muy adecuado el uso de MessageBox para comunicar informaci&amp;oacute;n al usuario acerca de la ejecuci&amp;oacute;n del paquete, ya que estimamos que en un alto porcentaje de las ocasiones, un paquete de estas caracter&amp;iacute;sticas se desarrolla para su ejecuci&amp;oacute;n desatendida a trav&amp;eacute;s de una tarea (Job) del Agente de SQL Server.&lt;/p&gt;
&lt;p&gt;Si bien con el depurador podemos obtener toda la informaci&amp;oacute;n necesaria en tiempo de ejecuci&amp;oacute;n, su uso se limita a Visual Studio, por lo que solamente puede ser utilizado durante la fase de desarrollo del paquete. Debemos, por lo tanto, encontrar un medio alternativo para poder informar al usuario de lo que est&amp;aacute; sucediendo durante la ejecuci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;La soluci&amp;oacute;n a este problema la encontramos en el m&amp;eacute;todo &lt;a href="http://msdn.microsoft.com/en-us/library/microsoft.sqlserver.dts.runtime.idtscomponentevents.fireinformation(v=SQL.110).aspx"&gt;Dts.Events.FireInformation&lt;/a&gt;, que hace que el paquete env&amp;iacute;e un evento informativo al exterior. Sustituyendo la llamada a MessageBox.Show por este otro m&amp;eacute;todo, nuestro c&amp;oacute;digo quedar&amp;aacute; como vemos a continuaci&amp;oacute;n.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; bOtraVez = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (Database oDatabase &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oServer.Databases)&lt;br /&gt;{&lt;br /&gt;    Dts.Events.FireInformation(0, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, &lt;span style="color:#006080;"&gt;&amp;quot;Procesando BBDD: &amp;quot;&lt;/span&gt; + oDatabase.Name, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty, 0, &lt;span style="color:#0000ff;"&gt;ref&lt;/span&gt; bOtraVez);&lt;br /&gt;}&lt;br /&gt;&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;De esta forma, al ejecutar el paquete podremos realizar un seguimiento en la ejecuci&amp;oacute;n del mismo desde la pesta&amp;ntilde;a &amp;quot;Execution Results&amp;quot; (&amp;quot;Progress&amp;quot; en tiempo de ejecuci&amp;oacute;n) del dise&amp;ntilde;ador, y tambi&amp;eacute;n desde la ventana &amp;quot;Output&amp;quot; del depurador, donde veremos los mensajes generados mediante el m&amp;eacute;todo FireInformation.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_11.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Ejecutando el paquete fuera del entorno de &lt;/b&gt;&lt;b&gt;SSBIDS&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Pero comprobemos, ejecutando el paquete de forma independiente, que estos mensajes de notificaci&amp;oacute;n tambi&amp;eacute;n funcionan fuera del entorno de SSBIDS. Supongamos que el archivo PckEstructurasBBDD.dtsx del proyecto de integraci&amp;oacute;n que estamos desarrollando se encuentra en la ruta C:\pruebasSSIS\EstructurasBBDD\EstructurasBBDD; lo primero que tenemos que hacer es iniciar SQL Server Management Studio (SSMS), conectando con el servicio &amp;quot;Integration Services&amp;quot; como vemos en la siguiente imagen.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_12.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n desplegaremos&amp;nbsp; los nodos &amp;quot;Stored Packages | File System&amp;quot;, haremos clic derecho en este &amp;uacute;ltimo, y seleccionaremos la opci&amp;oacute;n &amp;quot;Import Package&amp;quot;, abri&amp;eacute;ndose una ventana con el mismo nombre. En esta ventana desplegaremos la lista &amp;quot;Package location&amp;quot;, eligiendo &amp;quot;File System&amp;quot;, mientras que en el campo &amp;quot;Package path&amp;quot; introduciremos la ruta y el nombre del archivo .dtsx perteneciente al paquete que estamos programando. El nombre del paquete (campo Package name) se rellena por defecto con el mismo del archivo .dtsx, aunque podemos utilizar otro distinto.&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_13.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una vez completados los campos de esta ventana haremos clic en &amp;quot;OK&amp;quot;, siendo el paquete agregado al servidor de Integration Services de SQL Server.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_14.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Ejecutaremos el paquete haciendo clic derecho en el mismo y seleccionando la opci&amp;oacute;n &amp;quot;Run Package&amp;quot;, que abrir&amp;aacute; la ventana &amp;quot;Execute Package Utility&amp;quot;, en la que haremos clic en el bot&amp;oacute;n &amp;quot;Execute&amp;quot;.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_15.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esta ventana utiliza internamente el ejecutable DTExec.exe, que tambi&amp;eacute;n podemos usar desde una ventana &amp;quot;S&amp;iacute;mbolo del sistema&amp;quot;, como explicaremos en la segunda parte del art&amp;iacute;culo.&lt;/p&gt;
&lt;p&gt;Durante la ejecuci&amp;oacute;n del paquete, la ventana &amp;quot;Package Execution Progress&amp;quot; mostrar&amp;aacute; una serie de mensajes informativos acerca de su progreso, incluyendo aquellos que enviamos desde el c&amp;oacute;digo fuente utilizando el m&amp;eacute;todo FireInformation anteriormente explicado.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201110/UtilizandoSSISCrearScriptsRespaldoEstructuraBD_5F00_16.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Llegados a este punto hacemos una peque&amp;ntilde;a parada en el camino y concluimos esta primera parte del art&amp;iacute;culo. En la segunda entrega abordaremos la creaci&amp;oacute;n de los archivos de script que contendr&amp;aacute;n las sentencias para crear los objetos de nuestras bases de datos. Mientras tanto, el lector que quiera experimentar con el proyecto de integraci&amp;oacute;n desarrollado a lo largo del art&amp;iacute;culo, puede descargarlo &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201110/EstructurasBBDDzip.txt"&gt;aqu&amp;iacute;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Saludos.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=200913" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Business Intelligence" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Business+Intelligence/default.aspx" /><category term="Integration Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Integration+Services/default.aspx" /><category term="Data Warehouse" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Data+Warehouse/default.aspx" /><category term="SSIS" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SSIS/default.aspx" /></entry><entry><title>Pirámides de población con PowerPivot. Creación del gráfico (y 2)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/08/21/pir-225-mides-de-poblaci-243-n-con-powerpivot-creaci-243-n-del-gr-225-fico-y-2.aspx" /><id>/blogs/lmblanco/archive/2011/08/21/pir-225-mides-de-poblaci-243-n-con-powerpivot-creaci-243-n-del-gr-225-fico-y-2.aspx</id><published>2011-08-21T17:58:00Z</published><updated>2011-08-21T17:58:00Z</updated><content type="html">&lt;p&gt;En la primera parte de este art&amp;iacute;culo desarroll&amp;aacute;bamos un modelo de datos en PowerPivot que representaba las cifras de una poblaci&amp;oacute;n por edad y sexo. En esta segunda entrega plasmaremos dichas cifras en un gr&amp;aacute;fico con forma de pir&amp;aacute;mide de poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Gr&amp;aacute;fico de pir&amp;aacute;mide. Primer acercamiento&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En su estado actual, la tabla din&amp;aacute;mica ya tendr&amp;iacute;a la informaci&amp;oacute;n suficiente (cifras de poblaci&amp;oacute;n, edad y sexo) como para intentar crear un gr&amp;aacute;fico que represente una pir&amp;aacute;mide de poblaci&amp;oacute;n; aunque adelantamos al lector que en esta primera aproximaci&amp;oacute;n no vamos a conseguir el efecto deseado.&lt;/p&gt;
&lt;p&gt;Posicionados en la tabla din&amp;aacute;mica, dentro de la cinta de opciones de Excel seleccionaremos la opci&amp;oacute;n &amp;quot;Gr&amp;aacute;fico din&amp;aacute;mico&amp;quot;, perteneciente al grupo &amp;quot;Herramientas&amp;quot; de la ficha &amp;quot;Opciones&amp;quot;, que a su vez est&amp;aacute; contenida en la ficha de nivel superior &amp;quot;Herramientas de tabla din&amp;aacute;mica&amp;quot;.&lt;/p&gt;
&lt;p&gt;Esta selecci&amp;oacute;n abrir&amp;aacute; la ventana &amp;quot;Insertar gr&amp;aacute;fico&amp;quot;, que contiene el conjunto de tipos de gr&amp;aacute;fico disponibles. Aqu&amp;iacute; nos percataremos de que no existe una plantilla espec&amp;iacute;fica para crear un gr&amp;aacute;fico de pir&amp;aacute;mide; por lo tanto, entre toda la oferta a nuestra disposici&amp;oacute;n elegiremos, dentro de la categor&amp;iacute;a &amp;quot;Barra&amp;quot;, el tipo &amp;quot;Barra agrupada&amp;quot;, que como veremos m&amp;aacute;s adelante ser&amp;aacute; el que mejor se adaptar&amp;aacute; al resultado que queremos conseguir.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_22.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Aceptando esta ventana, el gr&amp;aacute;fico ser&amp;aacute; creado a partir de los datos de la tabla din&amp;aacute;mica, y tal y como hab&amp;iacute;amos anticipado, el resultado no se parecer&amp;aacute; a la imagen presentada al principio del art&amp;iacute;culo.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_23.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;No obstante, la principal diferencia radica en el dibujo de la barra correspondiente a la poblaci&amp;oacute;n de hombres, cuyo sentido deber&amp;iacute;a ser hacia la izquierda; el resto de aspectos son b&amp;aacute;sicamente cuestiones de configuraci&amp;oacute;n visual, que posteriormente explicaremos c&amp;oacute;mo resolver.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Solucionando la trayectoria de las barras de poblaci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Centr&amp;aacute;ndonos en la barra de poblaci&amp;oacute;n masculina, la soluci&amp;oacute;n para conseguir que se dibuje en direcci&amp;oacute;n opuesta a la que actualmente tiene, consiste en poner en negativo los valores de las celdas de la tabla din&amp;aacute;mica correspondientes a este segmento de la poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Si nos encontr&amp;aacute;ramos en una hoja de c&amp;aacute;lculo simple, sin conexi&amp;oacute;n a PowerPivot, la soluci&amp;oacute;n ser&amp;iacute;a tan sencilla como editar las celdas de la columna Hombre, pasando sus valores a negativo, pero estamos en un escenario de trabajo en el que los datos est&amp;aacute;n siendo obtenidos desde el modelo de datos de PowerPivot, por lo que no es posible editar directamente los valores de la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;Para solucionar esta clase de problemas tendremos que recurrir a la creaci&amp;oacute;n de columnas y/o medidas calculadas, que a trav&amp;eacute;s de expresiones DAX proporcionen los resultados que necesitamos. En el caso del paso a negativo de los valores de la columna Hombre, abriremos la ventana de PowerPivot, y situ&amp;aacute;ndonos en la primera columna vac&amp;iacute;a disponible en la tabla Poblaci&amp;oacute;n, escribiremos la siguiente expresi&amp;oacute;n en la barra de f&amp;oacute;rmulas:&lt;/p&gt;
&lt;p&gt;=IF([Sexo_ID] = &amp;quot;M&amp;quot;, 1, -1)&lt;/p&gt;
&lt;p&gt;Acabamos de crear una columna calculada que se evaluar&amp;aacute; para cada fila de la tabla Poblaci&amp;oacute;n, comprobando si el valor del campo Sexo_ID es igual a la letra &amp;quot;M&amp;quot;, en caso afirmativo, el valor de la columna en dicha fila ser&amp;aacute; 1, en caso contrario (cuando el campo contenga &amp;quot;H&amp;quot;) el valor devuelto ser&amp;aacute; -1.&lt;/p&gt;
&lt;p&gt;Seguidamente haremos doble clic sobre su cabecera para asignarle el nombre Sexo_Codigo. Tambi&amp;eacute;n podemos darle nombre haciendo clic derecho sobre la cabecera y eligiendo la opci&amp;oacute;n &amp;quot;Cambiar nombre de columna&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_24b.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Volviendo nuevamente a la ventana de Excel, eliminaremos el gr&amp;aacute;fico que hab&amp;iacute;amos creado en la hoja y desmarcaremos la medida RecuentoPoblacion, quedando vac&amp;iacute;a la zona de valores de la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;El pr&amp;oacute;ximo paso a dar consistir&amp;aacute; en crear una nueva medida con el nombre SumaPoblacion, basada en la siguiente expresi&amp;oacute;n DAX:&lt;/p&gt;
&lt;p&gt;=SUM( [Sexo_Codigo] )&lt;/p&gt;
&lt;p&gt;Al aplicar esta medida a la tabla din&amp;aacute;mica, la funci&amp;oacute;n SUM realiza la suma de los valores de la columna pasada como par&amp;aacute;metro, por lo que las cifras de la poblaci&amp;oacute;n de hombres ya aparecer&amp;aacute;n en negativo. Esto significa que al volver a crear el gr&amp;aacute;fico en el modo antes explicado, las barras indicadoras de los valores de poblaci&amp;oacute;n por sexo se dibujar&amp;aacute;n ahora en direcciones opuestas. Como detalle adicional, en la ficha &amp;quot;Herramientas de tabla din&amp;aacute;mica&amp;quot;, dentro de la ficha &amp;quot;Dise&amp;ntilde;o&amp;quot;, en el grupo &amp;quot;Dise&amp;ntilde;o&amp;quot; desplegaremos la opci&amp;oacute;n &amp;quot;Totales generales&amp;quot;, seleccionando el valor &amp;quot;Activado s&amp;oacute;lo para columnas&amp;quot;, que ocultar&amp;aacute; la columna de totales de fila, ya que su presencia en este contexto resulta irrelevante.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_25.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Configuraci&amp;oacute;n visual de las barras de poblaci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Aunque las barras del gr&amp;aacute;fico ya se muestran seg&amp;uacute;n el efecto que nos hab&amp;iacute;amos propuesto como objetivo, ser&amp;iacute;a deseable que su aspecto visual recibiera algunos retoques para mejorar la calidad de su presentaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;En primer lugar haremos clic derecho sobre las etiquetas de los rangos de edad, seleccionando la opci&amp;oacute;n &amp;quot;Dar formato a eje&amp;quot;. En la ventana del mismo nombre, dentro del apartado &amp;quot;Opciones del eje&amp;quot;, asignaremos el valor &amp;quot;Bajo&amp;quot; a la propiedad &amp;quot;Etiquetas del eje&amp;quot;, lo que tendr&amp;aacute; como resultado que esta columna de etiquetas quede alineada a la izquierda del gr&amp;aacute;fico.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_26.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n haremos clic derecho sobre cualquiera de las barras del gr&amp;aacute;fico, eligiendo la opci&amp;oacute;n &amp;quot;Dar formato a serie de datos&amp;quot;. En la ventana de configuraci&amp;oacute;n de la serie, dentro del apartado &amp;quot;Opciones de la serie&amp;quot;, en la propiedad &amp;quot;Superposici&amp;oacute;n de series&amp;quot;, desplazaremos el marcador de posici&amp;oacute;n hasta el extremo derecho (totalmente superpuesta), mientras que en la propiedad &amp;quot;Ancho del intervalo&amp;quot; desplazaremos el marcador de posici&amp;oacute;n hasta el extremo izquierdo (sin intervalo en absoluto). De esta forma conseguiremos que las barras aumenten su grosor y eliminen el espacio intermedio entre las mismas, quedando completamente unidas para formar la pir&amp;aacute;mide de poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_27.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Calculando la poblaci&amp;oacute;n en porcentajes&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;La representaci&amp;oacute;n de los datos obtenida hasta este momento, tanto en la tabla din&amp;aacute;mica como en el gr&amp;aacute;fico de pir&amp;aacute;mide, se basa en cifras absolutas de poblaci&amp;oacute;n. Sin embargo, lo habitual y recomendable es que dicha representaci&amp;oacute;n se realice como proporci&amp;oacute;n de cada grupo de edad y sexo sobre el total de la poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Por ejemplo, en nuestra tabla din&amp;aacute;mica, la poblaci&amp;oacute;n de mujeres con edades comprendidas entre los 55 y 59 a&amp;ntilde;os es de 184.888 personas; para obtener el porcentaje que este grupo de poblaci&amp;oacute;n constituye en relaci&amp;oacute;n al total de individuos con el que estamos trabajando (6.458.684), dividiremos el grupo entre el total, y formatearemos el resultado como porcentaje, obteniendo 2,86 %.&lt;/p&gt;
&lt;p&gt;Si queremos que la tabla din&amp;aacute;mica realice esta operaci&amp;oacute;n para todos los grupos de poblaci&amp;oacute;n tendremos que a&amp;ntilde;adir c&amp;aacute;lculos adicionales en forma de medidas, pero antes de eso eliminaremos el actual gr&amp;aacute;fico de poblaci&amp;oacute;n, ya que volveremos a construirlo a partir de una de las nuevas medidas.&lt;/p&gt;
&lt;p&gt;Partimos de la existencia de una medida, SumaPoblacion, que como ya sabemos, devuelve la cifra de poblaci&amp;oacute;n sumando el campo Sexo_Codigo. El siguiente paso consistir&amp;aacute; en crear una nueva medida, que al incluirse en la tabla din&amp;aacute;mica, proporcione el total de poblaci&amp;oacute;n en todas las celdas.&lt;/p&gt;
&lt;p&gt;Nuestra primera reacci&amp;oacute;n podr&amp;iacute;a ser volver a utilizar la medida RecuentoPoblacion, creada en las fases iniciales de nuestro ejemplo, pero pronto nos daremos cuenta de que no sirve para este prop&amp;oacute;sito, ya que aunque esta medida cuenta las filas de la tabla Poblaci&amp;oacute;n, los resultados de las celdas se ven afectados por los campos utilizados en filas y columnas, as&amp;iacute; como otros filtros que pudiera tener activos la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;Para que una medida cuente siempre todas las filas de una tabla, sin importar los filtros que pueda haber activos, utilizaremos la funci&amp;oacute;n CALCULATE, a la que pasaremos como primer par&amp;aacute;metro la operaci&amp;oacute;n a realizar, en este caso el recuento de filas de la tabla Poblaci&amp;oacute;n mediante la funci&amp;oacute;n COUNTROWS. A continuaci&amp;oacute;n pasaremos tantos par&amp;aacute;metros como filtros queramos eliminar, utilizando la funci&amp;oacute;n ALL(NombreTabla) por cada tabla que de alguna manera est&amp;eacute; actuando como filtro.&lt;/p&gt;
&lt;p&gt;Bajo tales premisas crearemos una nueva medida llamada TotalGlobalPoblacion, con la siguiente expresi&amp;oacute;n DAX:&lt;/p&gt;
&lt;p&gt;=CALCULATE(&amp;nbsp; COUNTROWS( Poblacion ), ALL( Edad), ALL( Sexo ) )&lt;/p&gt;
&lt;p&gt;Al aplicar sobre la tabla din&amp;aacute;mica esta medida, todas sus celdas mostrar&amp;aacute;n el mismo valor: el&amp;nbsp; total de la poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_28.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Ahora necesitamos una tercera medida que haga la divisi&amp;oacute;n entre las dos anteriores y muestre el resultado en formato porcentaje. Esta nueva medida tendr&amp;aacute; el &amp;quot;original&amp;quot; nombre de PorcentajePoblacion y utilizara la siguiente f&amp;oacute;rmula:&lt;/p&gt;
&lt;p&gt;=[SumaPoblacion] / [TotalGlobalPoblacion]&lt;/p&gt;
&lt;p&gt;Como ya vimos en la primera entrega del art&amp;iacute;culo, para aplicar el formato a esta medida haremos clic derecho en una de sus celdas eligiendo la opci&amp;oacute;n &amp;quot;Formato de n&amp;uacute;mero&amp;quot;. En la ventana de formato seleccionaremos esta vez la categor&amp;iacute;a &amp;quot;Personalizada&amp;quot;, a trav&amp;eacute;s de la cual introduciremos en el campo &amp;quot;Tipo&amp;quot; la siguiente cadena de formato propia.&lt;/p&gt;
&lt;p&gt;0,00%;0,00%&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_29.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esta cadena, adem&amp;aacute;s de formatear el n&amp;uacute;mero como porcentaje, mostrar&amp;aacute; sin el signo negativo los valores de la columna de poblaci&amp;oacute;n masculina, aunque internamente, dichos valores seguir&amp;aacute;n siendo negativos.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_30.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n desactivaremos todas las medidas de la tabla din&amp;aacute;mica a excepci&amp;oacute;n de PorcentajePoblaci&amp;oacute;n, que ser&amp;aacute; la &amp;uacute;nica que permanecer&amp;aacute; visible. Seguidamente volveremos a a&amp;ntilde;adir un gr&amp;aacute;fico de barras agrupadas, en el que adem&amp;aacute;s de utilizar los pasos de configuraci&amp;oacute;n explicados con anterioridad, agregaremos nuevas caracter&amp;iacute;sticas de formato para mejorar su presentaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Aplicar formato de porcentaje al eje horizontal &lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En primer lugar haremos clic derecho en el eje horizontal de etiquetas seleccionando la opci&amp;oacute;n &amp;quot;Dar formato a eje&amp;quot;, que abrir&amp;aacute; la ventana de formato, en cuyo apartado &amp;quot;N&amp;uacute;mero&amp;quot; seleccionaremos la categor&amp;iacute;a de formato &amp;quot;Personalizado&amp;quot; y en el campo &amp;quot;C&amp;oacute;digo de formato&amp;quot; escribiremos la siguiente cadena de formato:&lt;/p&gt;
&lt;p&gt;0%;0%&lt;/p&gt;
&lt;p&gt;Haciendo clic en el bot&amp;oacute;n &amp;quot;Agregar&amp;quot;, la cadena se a&amp;ntilde;adir&amp;aacute; a la lista de cadenas personalizadas, de modo que al aceptar la ventana se aplicar&amp;aacute; el formato al eje horizontal de etiquetas.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_31.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Remarcando los bordes de las barras de poblaci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Seguidamente haremos clic sobre alguna de las barras del gr&amp;aacute;fico, volviendo a elegir la opci&amp;oacute;n &amp;quot;Dar formato a serie de datos&amp;quot;. En esta ocasi&amp;oacute;n, dentro del apartado &amp;quot;Color del borde&amp;quot; haremos clic en la opci&amp;oacute;n &amp;quot;L&amp;iacute;nea s&amp;oacute;lida&amp;quot;, seleccionando el color negro; mientras que en el apartado &amp;quot;Estilos del borde&amp;quot; asignaremos a la propiedad &amp;quot;Ancho&amp;quot; el valor &amp;quot;2 pto&amp;quot;. Esta operaci&amp;oacute;n la realizaremos para ambos grupos de barras del gr&amp;aacute;fico.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_32.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Despu&amp;eacute;s haremos clic derecho sobre las etiquetas de los rangos de edad, seleccionando la opci&amp;oacute;n &amp;quot;Dar formato a eje&amp;quot;. En esta ventana de formato asignaremos los mismos valores para las propiedades de color y estilo de borde que acabamos de utilizar para las barras del gr&amp;aacute;fico.&lt;/p&gt;
&lt;p&gt;Como resultado de estas acciones, el gr&amp;aacute;fico mostrar&amp;aacute; sus bordes con un contorno claramente remarcado.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_33.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Reubicando la posici&amp;oacute;n de la leyenda&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En el momento de crear el gr&amp;aacute;fico, Excel sit&amp;uacute;a por defecto la leyenda (campo Sexo_DS) en el lado derecho. No obstante, es posible cambiar la ubicaci&amp;oacute;n de este elemento si queremos proporcionar m&amp;aacute;s espacio al dibujo de las barras de poblaci&amp;oacute;n. Para ello, haremos clic derecho en la leyenda y seleccionaremos la opci&amp;oacute;n &amp;quot;Formato de leyenda&amp;quot;, en la ventana de formato, dentro del apartado &amp;quot;Opciones de leyenda&amp;quot;, haremos clic en la opci&amp;oacute;n &amp;quot;Superior&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_34.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Como podemos apreciar, el gr&amp;aacute;fico ha ganado en superficie de dibujo, pero los indicadores de la leyenda han quedado colocados en orden inverso a las barras. Para solucionar este problema haremos clic en el bot&amp;oacute;n de campos de la leyenda (Sexo_DS), de forma que despleguemos sus opciones de filtro, donde seleccionaremos &amp;quot;Ordenar de Z a A&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_35.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Con esta acci&amp;oacute;n, los indicadores de leyenda quedar&amp;aacute;n colocados adecuadamente, pero ahora nos encontraremos con el inconveniente de que los colores de las barras han quedado invertidos, y hemos perdido el borde de las barras del gr&amp;aacute;fico.&lt;/p&gt;
&lt;p&gt;Restauraremos los bordes de las barras en la manera explicada anteriormente, mientras que en cuanto a los colores, para cada lado de la pir&amp;aacute;mide haremos clic derecho en una de las barras, y en la opci&amp;oacute;n &amp;quot;Relleno de forma&amp;quot;, cambiaremos el color actual por el que originalmente ten&amp;iacute;a el gr&amp;aacute;fico.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_36.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para completar los ajustes que estamos realizando sobre la leyenda, arrastraremos &amp;eacute;sta hasta que quede situada al nivel del elemento superior de la pir&amp;aacute;mide, y aumentaremos su anchura, para que los indicadores queden m&amp;aacute;s separados.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_37.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Despejar el &amp;aacute;rea de campos y agregar t&amp;iacute;tulo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Seguidamente haremos clic derecho en cualquiera de los botones de campos del gr&amp;aacute;fico y seleccionaremos la opci&amp;oacute;n &amp;quot;Ocultar todos los botones de campos en gr&amp;aacute;fico&amp;quot;. Con este movimiento impediremos que el usuario aplique filtros sobre el eje horizontal y/o vertical de la pir&amp;aacute;mide, manteniendo su estructura consistente y evitando as&amp;iacute; la posibilidad, por ejemplo, de ocultar rangos de edad o alguno de los sexos. No obstante, seguir&amp;aacute; existiendo tal posibilidad de filtro desde la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_38.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Por otra parte, en el grupo de fichas &amp;quot;Herramientas del gr&amp;aacute;fico din&amp;aacute;mico&amp;quot; haremos clic en la ficha &amp;quot;Presentaci&amp;oacute;n&amp;quot;, y dentro del grupo &amp;quot;Etiquetas&amp;quot; haremos clic en la opci&amp;oacute;n &amp;quot;T&amp;iacute;tulo del gr&amp;aacute;fico&amp;quot;, que desplegar&amp;aacute; una serie de elementos entre los que elegiremos &amp;quot;Encima del gr&amp;aacute;fico&amp;quot;, a&amp;ntilde;adi&amp;eacute;ndose un cuadro de texto al gr&amp;aacute;fico, que editaremos para asignarle un t&amp;iacute;tulo. Llegados a este punto habremos completado el desarrollo de nuestra pir&amp;aacute;mide de poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_39.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Dinamizando los datos de la pir&amp;aacute;mide mediante segmentaciones&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Aunque hemos logrado el objetivo propuesto de crear una pir&amp;aacute;mide de poblaci&amp;oacute;n, resultar&amp;iacute;a interesante dotarla de cierto valor a&amp;ntilde;adido, tal y como vamos a hacer en este apartado.&lt;/p&gt;
&lt;p&gt;Si observamos el modelo de datos en la ventana de PowerPivot, caeremos en la cuenta de que todav&amp;iacute;a no hemos hecho uso de la informaci&amp;oacute;n que sobre zonificaci&amp;oacute;n sanitaria existe en el mismo, por lo que podemos aprovechar estos datos para construir un filtro que muestre la pir&amp;aacute;mide en base a la poblaci&amp;oacute;n de una o varias de estas zonas sanitarias.&lt;/p&gt;
&lt;p&gt;Las tablas din&amp;aacute;micas de PowerPivot, adem&amp;aacute;s del filtro tradicional, incorporan un nuevo tipo de filtro denominado &amp;quot;segmentaci&amp;oacute;n&amp;quot;, que adem&amp;aacute;s de la funcionalidad habitual de filtrado ofrece una interfaz de usuario m&amp;aacute;s flexible para la manipulaci&amp;oacute;n de los valores a tratar.&lt;/p&gt;
&lt;p&gt;Vamos a crear en nuestra pir&amp;aacute;mide una segmentaci&amp;oacute;n basada en la informaci&amp;oacute;n de zona. Para ello, en el panel de la lista de campos, arrastraremos el campo Zona_DS de la tabla Zona hasta el bloque &amp;quot;Segmentaciones de datos horizontales&amp;quot;, obteniendo como resultado una segmentaci&amp;oacute;n situada encima de la tabla din&amp;aacute;mica y el gr&amp;aacute;fico de pir&amp;aacute;mide.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_40.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para filtrar los datos mediante la segmentaci&amp;oacute;n simplemente tenemos que seleccionar el nombre de la zona sanitaria que queramos emplear como filtro. Tambi&amp;eacute;n es posible filtrar simult&amp;aacute;neamente varias zonas manteniendo pulsada la tecla Ctrl, mientras vamos haciendo clic en las zonas a filtrar (como muestra la siguiente figura). Si queremos eliminar todos los filtros activos haremos clic en el icono situado a tal efecto en la parte superior derecha de la segmentaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_41.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Y llegados a este punto damos por finalizado el art&amp;iacute;culo, en el que a lo largo de sus dos entregas hemos mostrado el modo de construir una pir&amp;aacute;mide de poblaci&amp;oacute;n en Excel 2010, utilizando PowerPivot como herramienta de gesti&amp;oacute;n de los datos poblacionales. No obstante, la potencia de esta tecnolog&amp;iacute;a va m&amp;aacute;s all&amp;aacute; del mero tratamiento de la informaci&amp;oacute;n demogr&amp;aacute;fica, abarcando su campo de acci&amp;oacute;n a cualquier entorno en el que tengamos que realizar un an&amp;aacute;lisis con elevados vol&amp;uacute;menes de datos.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=199789" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="PowerPivot" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx" /></entry><entry><title>Pirámides de población con PowerPivot. Preparación del entorno de datos (1)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/08/18/pir-225-mides-de-poblaci-243-n-con-powerpivot-preparaci-243-n-del-entorno-de-datos-1.aspx" /><id>/blogs/lmblanco/archive/2011/08/18/pir-225-mides-de-poblaci-243-n-con-powerpivot-preparaci-243-n-del-entorno-de-datos-1.aspx</id><published>2011-08-18T19:13:00Z</published><updated>2011-08-18T19:13:00Z</updated><content type="html">&lt;p&gt;Una pir&amp;aacute;mide poblacional es una herramienta que nos permite analizar el estado y evoluci&amp;oacute;n de una poblaci&amp;oacute;n en funci&amp;oacute;n de su edad y sexo. Se trata de un elemento caracter&amp;iacute;stico en demograf&amp;iacute;a y estad&amp;iacute;stica, aunque sus aplicaciones tambi&amp;eacute;n abarcan campos tales como el sanitario, educativo, comercial, etc. Es por ello, que su integraci&amp;oacute;n en un sistema de informaci&amp;oacute;n perteneciente a alguna de las &amp;aacute;reas reci&amp;eacute;n mencionadas, supone un enriquecimiento sustancial en la calidad de los resultados obtenidos por los usuarios de tales sistemas.&lt;/p&gt;
&lt;p&gt;En el presente art&amp;iacute;culo abordaremos la construcci&amp;oacute;n de pir&amp;aacute;mides de poblaci&amp;oacute;n utilizando PowerPivot, un complemento para Excel 2010, que permite el acceso a or&amp;iacute;genes de datos de gran volumen, as&amp;iacute; como su posterior manejo y an&amp;aacute;lisis.&lt;/p&gt;
&lt;p&gt;Como ya apunt&amp;aacute;bamos en el art&amp;iacute;culo &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/07/18/generaci-243-n-de-datos-demogr-225-ficos-desde-sql-server.aspx"&gt;Generaci&amp;oacute;n de datos demogr&amp;aacute;ficos desde SQL Server&lt;/a&gt;, publicado en este mismo blog, nuestro objetivo actual (utilizando la base de datos PiramidePoblacion creada en el mencionado art&amp;iacute;culo) consistir&amp;aacute; en construir un gr&amp;aacute;fico que &amp;nbsp;represente una pir&amp;aacute;mide de poblaci&amp;oacute;n similar a la que vemos&amp;nbsp; en la siguiente figura.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_01.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La primera parte del art&amp;iacute;culo estar&amp;aacute; dedicada a la preparaci&amp;oacute;n del modelo de datos de PowerPivot: conexi&amp;oacute;n contra un origen de datos, carga y creaci&amp;oacute;n de una tabla din&amp;aacute;mica para analizar las cifras de poblaci&amp;oacute;n. La segunda parte la destinaremos a la construcci&amp;oacute;n del gr&amp;aacute;fico que represente a la pir&amp;aacute;mide de poblaci&amp;oacute;n, partiendo de los datos sobre los que hemos trabajado en la primera entrega.&lt;/p&gt;
&lt;p&gt;Al igual que en el art&amp;iacute;culo mencionado anteriormente, quiero agradecer nuevamente a los integrantes del Servicio de Informes de Salud y Estudios (Subdirecci&amp;oacute;n de Promoci&amp;oacute;n de la Salud y Prevenci&amp;oacute;n, DG Atenci&amp;oacute;n Primaria, Consejer&amp;iacute;a Sanidad CM): Jenaro Astray Mochales, Mar&amp;iacute;a Felicitas Dom&amp;iacute;nguez Berj&amp;oacute;n, Mar&amp;iacute;a Dolores Esteban Vasallo, Beatriz Elvira Rodr&amp;iacute;guez y en especial a Ricard G&amp;egrave;nova Maleras, el soporte y orientaci&amp;oacute;n recibido sobre los conceptos demogr&amp;aacute;ficos necesarios con los que poder desarrollar apropiadamente una pir&amp;aacute;mide de poblaci&amp;oacute;n utilizando Excel 2010 en combinaci&amp;oacute;n con PowerPivot. Adem&amp;aacute;s de todo esto, Ricard ha accedido muy gustosamente a realizar una estupenda labor de revisi&amp;oacute;n de este art&amp;iacute;culo, con lo que el agradecimiento va por partida doble.&lt;/p&gt;
&lt;p&gt;Igualmente quisiera expresar mi agradecimiento a Enrique Barcel&amp;oacute; por todos sus estupendos trucos sobre desarrollo OLAP, que comparte con el equipo de trabajo, y que hacen un poco m&amp;aacute;s f&amp;aacute;cil nuestra labor de desarrollo en estas tareas del Business Intelligence.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Un poco de teor&amp;iacute;a&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Pero antes de entrar de lleno en su proceso de creaci&amp;oacute;n, vamos a proporcionar unos breves apuntes te&amp;oacute;ricos sobre las pir&amp;aacute;mides de poblaci&amp;oacute;n, que nos permitan entender mejor cu&amp;aacute;les son sus principales caracter&amp;iacute;sticas y la informaci&amp;oacute;n que de ellas podemos obtener y analizar.&lt;/p&gt;
&lt;p&gt;En esencia, una pir&amp;aacute;mide de poblaci&amp;oacute;n es un doble histograma que representa la distribuci&amp;oacute;n por edad y sexo de los efectivos de una poblaci&amp;oacute;n, bien en cifras absolutas, bien como porcentaje sobre la poblaci&amp;oacute;n total.&lt;/p&gt;
&lt;p&gt;Si estamos interesados en obtener una informaci&amp;oacute;n m&amp;aacute;s detallada acerca de los aspectos conceptuales que rodean a las pir&amp;aacute;mides de poblaci&amp;oacute;n, la ayuda del programa &lt;a href="http://www.sergas.es/MostrarContidos_N3_T01.aspx?IdPaxina=62714"&gt;Epidat 4.0&lt;/a&gt; puede resultarnos de utilidad. Se trata de una aplicaci&amp;oacute;n desarrollada por la &lt;a href="http://www.sergas.es/MostrarContidos_N3_T01.aspx?IdPaxina=62713"&gt;Consejer&amp;iacute;a de Sanidad de la Xunta de Galicia&lt;/a&gt; y la &lt;a href="http://new.paho.org/blogs/esp/?p=694"&gt;Organizaci&amp;oacute;n Panamericana de la Salud&lt;/a&gt; (OPS, Washington), de cuya documentaci&amp;oacute;n citamos a continuaci&amp;oacute;n algunos de los puntos m&amp;aacute;s importantes en relaci&amp;oacute;n con el tema que nos ocupa. En primer lugar comenzaremos con algunas nociones relativas a la construcci&amp;oacute;n de la pir&amp;aacute;mide de poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;quot;El mejor modo de visualizar la distribuci&amp;oacute;n por sexo y edad de una poblaci&amp;oacute;n es, sin duda, la pir&amp;aacute;mide de poblaci&amp;oacute;n, verdadero icono de la demograf&amp;iacute;a. Una pir&amp;aacute;mide es un doble histograma que permite, con un solo golpe de vista, hacerse una idea clara no s&amp;oacute;lo acerca de las caracter&amp;iacute;sticas generales de la poblaci&amp;oacute;n (joven, envejecida, con alg&amp;uacute;n desequilibrio en funci&amp;oacute;n del sexo) sino tambi&amp;eacute;n sobre particularidades espec&amp;iacute;ficas que remiten a alg&amp;uacute;n acontecimiento concreto concerniente a la poblaci&amp;oacute;n objeto de estudio.&lt;/p&gt;
&lt;p&gt;Usualmente las pir&amp;aacute;mides de poblaci&amp;oacute;n se construyen siguiendo varias convenciones y reglas:&lt;/p&gt;
&lt;p&gt;- representar a los hombres a la izquierda y a las mujeres a la derecha del eje central,&lt;/p&gt;
&lt;p&gt;- ubicar las edades de manera que cuanto m&amp;aacute;s bajas sean, m&amp;aacute;s cerca est&amp;eacute;n de la base y viceversa,&lt;/p&gt;
&lt;p&gt;- mantener cierta proporcionalidad entre base y altura (3 anchuras por 2 alturas, o 4 por 3, aproximadamente),&lt;/p&gt;
&lt;p&gt;- respetar la misma escala a ambos lados del eje central (para favorecer la comparaci&amp;oacute;n entre sexos),&lt;/p&gt;
&lt;p&gt;- representar el peso de cada intervalo etario por la superficie de cada barra del histograma, no por su longitud, algo especialmente importante cuando se trabaja con grupos de edad desiguales,&lt;/p&gt;
&lt;p&gt;- pueden construirse con valores absolutos, pero es preferible hacerlo con las proporciones de cada edad y sexo respecto de la poblaci&amp;oacute;n total. &lt;/p&gt;
&lt;p&gt;El &amp;uacute;ltimo punto es importante y diferencia a la pir&amp;aacute;mide de los indicadores de estructura [proporci&amp;oacute;n de j&amp;oacute;venes o ancianos, &amp;iacute;ndice de envejecimiento, etc.], que se calculan separadamente sobre el total de cada sexo respectivo. En el caso de la pir&amp;aacute;mide de poblaci&amp;oacute;n, usar como denominador de las proporciones a la poblaci&amp;oacute;n total de ambos sexos reunidos garantiza la comparabilidad no s&amp;oacute;lo de la distribuci&amp;oacute;n por edad, sino tambi&amp;eacute;n por sexo&amp;quot;.&lt;/p&gt;
&lt;p&gt;Y finalizaremos con aquellas cuestiones relacionadas con la interpretaci&amp;oacute;n de la pir&amp;aacute;mide.&lt;/p&gt;
&lt;p&gt;&amp;quot;Una pir&amp;aacute;mide por sexo y edad resume la historia demogr&amp;aacute;fica de una poblaci&amp;oacute;n de por lo menos los cien a&amp;ntilde;os anteriores a la fecha de referencia (el tiempo que tarda, aproximadamente, una generaci&amp;oacute;n en pasar de la base a la cima de la pir&amp;aacute;mide). En ocasiones, el efecto indirecto de algunos acontecimientos demogr&amp;aacute;ficos es visible m&amp;aacute;s all&amp;aacute; de ese salto de un siglo (por ejemplo, el impacto del profundo descenso de la fecundidad de las &amp;uacute;ltimas d&amp;eacute;cadas experimentado por muchas poblaciones se apreciar&amp;aacute;, sin duda, en las pir&amp;aacute;mides de la primera mitad del siglo XXII). Una pir&amp;aacute;mide por edades simples [edad por edad: 0, 1, 2, 3 ... 99, 100 ...] permite un an&amp;aacute;lisis m&amp;aacute;s preciso que otra realizada por grupos de edades agregadas (quinquenales, decenales), pero corre tambi&amp;eacute;n el riesgo de verse afectada por problemas de calidad de los registros, o ser vulnerable a la inestabilidad de las distribuciones en poblaciones peque&amp;ntilde;as.&lt;/p&gt;
&lt;p&gt;La primera percepci&amp;oacute;n de una pir&amp;aacute;mide permite identificar los rasgos generales de la poblaci&amp;oacute;n representada: una pir&amp;aacute;mide de base ancha y que se estrecha r&amp;aacute;pidamente da idea de una poblaci&amp;oacute;n joven, con una alta proporci&amp;oacute;n de ni&amp;ntilde;os y adolescentes, y baja de adultos y ancianos, resultado de una alta natalidad y mortalidad. Inversamente, una pir&amp;aacute;mide con perfil estrecho en la base y ancho en el centro y la cima representa una estructura madura o envejecida. Cuanto mayor es la esperanza de vida de una poblaci&amp;oacute;n, mayor suele ser la desigualdad por sexo en la cima de la pir&amp;aacute;mide (m&amp;aacute;s llena por el lado de las mujeres, por su mayor nivel de supervivencia).&lt;/p&gt;
&lt;p&gt;La pir&amp;aacute;mide no da respuestas por s&amp;iacute; misma, sino que propicia que se planteen preguntas pertinentes. Las explicaciones para su perfil deben buscarse en la historia, en los avatares sociales, pol&amp;iacute;ticos, econ&amp;oacute;micos, que generan consecuencias en el devenir demogr&amp;aacute;fico -es decir, en la fecundidad, la mortalidad o la migraci&amp;oacute;n, que son los fen&amp;oacute;menos que modelan el contorno y fijan el tama&amp;ntilde;o de una poblaci&amp;oacute;n- y que tienen una interpretaci&amp;oacute;n en funci&amp;oacute;n de la triple perspectiva temporal: edad, periodo y cohorte&amp;quot;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Incorporando los datos a PowerPivot&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Gracias a VertiPaq, el motor de procesamiento de datos de PowerPivot, podemos conseguir una potencia y velocidad sin precedentes en la manipulaci&amp;oacute;n, filtrado, creaci&amp;oacute;n de expresiones de l&amp;oacute;gica de negocio, y en definitiva, en todas aquellas operaciones anal&amp;iacute;ticas que debamos realizar sobre un modelo de datos creado con esta herramienta.&lt;/p&gt;
&lt;p&gt;El siguiente &lt;a href="http://www.powerpivot.com/"&gt;enlace&lt;/a&gt; proporciona acceso a la p&amp;aacute;gina principal de PowerPivot, desde donde podremos descargarlo, para posteriormente instalarlo en nuestra m&amp;aacute;quina, de forma que podamos seguir los ejemplos del art&amp;iacute;culo.&lt;/p&gt;
&lt;p&gt;Una vez que hayamos instalado PowerPivot iniciaremos Excel 2010, cre&amp;aacute;ndose una nueva hoja de c&amp;aacute;lculo a la que daremos el nombre PiramidePoblacion.xlsx. En la cinta de opciones dispondremos ahora de una nueva ficha con el nombre &amp;quot;PowerPivot&amp;quot;. Al hacer clic en la misma seleccionaremos la opci&amp;oacute;n &amp;quot;Ventana de PowerPivot&amp;quot;, perteneciente al grupo &amp;quot;Iniciar&amp;quot;, lo que abrir&amp;aacute; la mencionada ventana de trabajo de PowerPivot, en la que definiremos la estructura de tablas que vamos a utilizar, o &amp;quot;modelo de datos&amp;quot;, tal y c&amp;oacute;mo se denomina dentro del contexto de PowerPivot.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_02.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_02.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n, en la pesta&amp;ntilde;a &amp;quot;P&amp;aacute;gina principal&amp;quot; de la ventana de PowerPivot, nos conectaremos a la base de datos mediante la opci&amp;oacute;n &amp;quot;Desde base de datos | De SQL Server&amp;quot;, situada en el grupo &amp;quot;Obtener datos externos&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_03.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_03.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esta acci&amp;oacute;n iniciar&amp;aacute; el asistente para importar tablas, en el que indicaremos el origen de datos al que nos queremos conectar.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_04.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_04.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una fuente de datos v&amp;aacute;lida para elaborar una pir&amp;aacute;mide de poblaci&amp;oacute;n ha de tener como m&amp;iacute;nimo informaci&amp;oacute;n acerca del sexo y edad de la poblaci&amp;oacute;n, como es el caso de nuestra base de datos PiramidePoblacion. Adicionalmente, y como forma de enriquecer el an&amp;aacute;lisis a realizar, la base de datos puede disponer de informaci&amp;oacute;n complementaria como pudiera ser la zonificaci&amp;oacute;n sanitaria, nacionalidad de la poblaci&amp;oacute;n, etc.&lt;/p&gt;
&lt;p&gt;Tras elegir la base de datos PiramidePoblacion, el siguiente paso nos ofrecer&amp;aacute; una lista de las tablas y vistas que podremos importar, donde marcaremos las siguientes: Edad, Poblaci&amp;oacute;n, Sexo y Zona, comenzando la importaci&amp;oacute;n al hacer clic en el bot&amp;oacute;n &amp;quot;Finalizar&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_05.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_05.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Si la importaci&amp;oacute;n se desarrolla correctamente, el asistente mostrara una ventana resumen del proceso.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_06.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_06.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una vez terminada la incorporaci&amp;oacute;n de datos haremos clic en &amp;quot;Cerrar&amp;quot; para volver a la ventana de PowerPivot, donde hallaremos organizadas en diversas pesta&amp;ntilde;as cada una de las tablas importadas.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_07.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;An&amp;aacute;lisis mediante tabla din&amp;aacute;mica&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Antes de pasar a la fase de construcci&amp;oacute;n de la pir&amp;aacute;mide de poblaci&amp;oacute;n, vamos a utilizar una tabla din&amp;aacute;mica de PowerPivot para analizar las cifras del modelo de datos, por lo que situados en su ventana de trabajo haremos clic en la opci&amp;oacute;n &amp;quot;PivotTable&amp;quot;, perteneciente al grupo &amp;quot;Informes&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_08.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Esta acci&amp;oacute;n nos posicionar&amp;aacute; en la ventana de Excel, donde se abrir&amp;aacute; un di&amp;aacute;logo en el que elegiremos la hoja de c&amp;aacute;lculo en la que se ubicar&amp;aacute; la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_09.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_09.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En nuestro caso seleccionaremos la primera opci&amp;oacute;n y aceptaremos el di&amp;aacute;logo, cre&amp;aacute;ndose la tabla din&amp;aacute;mica en una nueva hoja c&amp;aacute;lculo&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_10.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_10.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Desde el panel &amp;quot;Lista de campos de PowerPivot&amp;quot; tenemos a nuestra disposici&amp;oacute;n los campos de las tablas del modelo de datos, que situaremos en las diferentes zonas de la tabla din&amp;aacute;mica (etiquetas de filas, columnas, valores, etc.) para llevar a cabo nuestras operaciones de an&amp;aacute;lisis. Utilizaremos para ello un estilo de trabajo muy semejante al que emplear&amp;iacute;amos si estuvi&amp;eacute;ramos consultando un cubo OLAP, ya que el manejo de los campos de PowerPivot en este sentido es similar al que podemos realizar con las dimensiones y medidas de un cubo de datos cuando es consultado desde Excel.&lt;/p&gt;
&lt;p&gt;Vamos a comenzar por una consulta sencilla, consistente en contar los registros de la tabla Poblaci&amp;oacute;n, agrupando la informaci&amp;oacute;n por rangos de edad, los cuales situaremos en las filas de la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;El recuento de registros lo realizaremos mediante una expresi&amp;oacute;n &lt;a href="http://social.technet.microsoft.com/wiki/contents/articles/powerpivot-data-analysis-expressions-dax-language.aspx"&gt;DAX&lt;/a&gt; (el lenguaje de consultas de PowerPivot) situada en una medida calculada, que crearemos seleccionando la opci&amp;oacute;n &amp;quot;Nueva medida&amp;quot;, perteneciente al grupo &amp;quot;Medidas&amp;quot; de la ficha &amp;quot;PowerPivot&amp;quot;. Esta medida la aplicaremos sobre la tabla Poblaci&amp;oacute;n, por lo que deberemos estar previamente posicionados en la misma, dentro del panel de la lista de campos.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_11.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_11.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Al seleccionar esta opci&amp;oacute;n se abrir&amp;aacute; la ventana &amp;quot;Configuraci&amp;oacute;n de medida&amp;quot;, en la que dentro del cuadro de texto reservado para la f&amp;oacute;rmula escribiremos la siguiente expresi&amp;oacute;n:&lt;/p&gt;
&lt;p&gt;=COUNTROWS(Poblacion)&lt;/p&gt;
&lt;p&gt;La funci&amp;oacute;n COUNTROWS, como su nombre indica, cuenta las filas de la tabla pasada como par&amp;aacute;metro. Para terminar la creaci&amp;oacute;n de nuestra medida le daremos el nombre &amp;quot;RecuentoPoblacion&amp;quot; y haremos clic en &amp;quot;Aceptar&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_12.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_12.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Nada m&amp;aacute;s terminar de crear la medida, &amp;eacute;sta se a&amp;ntilde;adir&amp;aacute; autom&amp;aacute;ticamente a la lista de campos de la tabla Poblaci&amp;oacute;n y al bloque &amp;quot;Valores&amp;quot;, visualiz&amp;aacute;ndose en la tabla din&amp;aacute;mica el n&amp;uacute;mero total de filas de la tabla.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_13.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_13.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n seleccionaremos, en el panel de la lista de campos, el campo Edad_Grupo de la tabla Edad, lo que situar&amp;aacute; autom&amp;aacute;ticamente al mencionado campo en el bloque &amp;quot;Etiquetas de fila&amp;quot;. Si este no fuera el comportamiento obtenido, arrastraremos manualmente el campo hasta colocarlo en dicho bloque.&lt;/p&gt;
&lt;p&gt;Como consecuencia de la acci&amp;oacute;n anterior la tabla din&amp;aacute;mica se ver&amp;aacute; actualizada, mostr&amp;aacute;ndose en el eje de las filas los valores del campo Edad_Grupo. Respecto a las cifras de la medida RecuentoPoblacion, &amp;eacute;stas deber&amp;iacute;an repartirse entre los tramos de cada edad, para as&amp;iacute; reflejar el n&amp;uacute;mero de registros (poblaci&amp;oacute;n) correspondiente a cada uno de dichos tramos. Sin embargo, como vemos en la siguiente figura, es algo que no est&amp;aacute; ocurriendo, ya que la medida muestra el mismo valor para todas las filas, lo cual es incorrecto.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_14.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_14.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Relaciones entre las tablas del modelo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Observando el panel de campos vemos que PowerPivot ya se ha percatado del problema que acabamos de comentar, porque en la parte superior de dicho panel aparece un aviso, que nos informa acerca de que puede ser necesaria una relaci&amp;oacute;n entre las tablas que se est&amp;aacute;n utilizando para componer la consulta de la tabla din&amp;aacute;mica.&lt;/p&gt;
&lt;p&gt;Este problema no habr&amp;iacute;a tenido lugar si hubiesen existido las oportunas relaciones entre las tablas de la base de datos, aunque como ya dijimos en el art&amp;iacute;culo sobre la creaci&amp;oacute;n de la base de datos de poblaci&amp;oacute;n, dichas relaciones no fueron creadas intencionadamente, para as&amp;iacute; demostrar que tambi&amp;eacute;n es posible hacerlo desde PowerPivot, como veremos a continuaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Para dejar que PowerPivot detecte autom&amp;aacute;ticamente la relaci&amp;oacute;n que necesita, haremos clic en el bot&amp;oacute;n &amp;quot;Crear&amp;quot; que aparece junto al aviso mostrado en el panel de campos. Como resultado se abrir&amp;aacute; una ventana encargada de crear la oportuna relaci&amp;oacute;n, ofreci&amp;eacute;ndonos informaci&amp;oacute;n adicional sobre la misma a trav&amp;eacute;s de los enlaces &amp;quot;Detalles&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_15.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_15.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una vez creada la relaci&amp;oacute;n, &amp;eacute;sta ser&amp;aacute; aplicada inmediatamente, sin intervenci&amp;oacute;n del usuario, sobre la tabla din&amp;aacute;mica, que de esta forma ya mostrar&amp;aacute; correctamente los valores de la medida agrupados por edad.&lt;/p&gt;
&lt;p&gt;Tambi&amp;eacute;n es posible crear manualmente las relaciones entre las tablas del modelo de datos utilizando la ventana de trabajo de PowerPivot. Para ello haremos clic en la opci&amp;oacute;n &amp;quot;Crear relaci&amp;oacute;n&amp;quot;, perteneciente al grupo &amp;quot;Relaciones&amp;quot;, que est&amp;aacute; situado en la ficha &amp;quot;Dise&amp;ntilde;o&amp;quot; de la mencionada ventana.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_16.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_16.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esta opci&amp;oacute;n abrir&amp;aacute; una ventana con el mismo nombre, en la que seleccionaremos la tabla y columna que representar&amp;aacute;n el origen y destino de la relaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_17.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_17.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;De esta forma estableceremos dos nuevas relaciones, que tendr&amp;aacute;n a la tabla Poblaci&amp;oacute;n como origen y a las tablas Sexo y Zona como destino. Adicionalmente, desde la opci&amp;oacute;n &amp;quot;Administrar relaciones&amp;quot; podemos ver un resumen de las relaciones creadas as&amp;iacute; como gestionarlas (crear, editar, eliminar, etc.).&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_18.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_18.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Estos cambios que acabamos de realizar en la ventana de PowerPivot pueden afectar directa o indirectamente a los datos que estamos presentando en la tabla din&amp;aacute;mica; por dicho motivo, al retornar a la ventana de Excel veremos un aviso al respecto en el panel de campos, donde haremos clic en el bot&amp;oacute;n &amp;quot;Actualizar&amp;quot;, para refrescar los datos con los que estamos trabajando.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_19.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_19.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Agregando datos en el eje de columnas&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Solucionado el problema de las relaciones, ahora es el momento de a&amp;ntilde;adir nuevos datos en las columnas de la tabla din&amp;aacute;mica mediante el campo Sexo_DS de la tabla Sexo.&lt;/p&gt;
&lt;p&gt;Al&amp;nbsp; ser seleccionado, este campo se situar&amp;aacute; por defecto en el bloque &amp;quot;Etiquetas de fila&amp;quot;, de modo que tendremos que moverlo manualmente hasta el bloque &amp;quot;Etiquetas de columna&amp;quot;; o bien al hacer clic en &amp;eacute;l lo arrastraremos directamente hasta el bloque de etiquetas de columna.&lt;/p&gt;
&lt;p&gt;Adicionalmente, daremos formato a las celdas num&amp;eacute;ricas haciendo clic derecho en cualquiera de ellas y seleccionando la opci&amp;oacute;n &amp;quot;Formato de n&amp;uacute;mero&amp;quot;, en el cuadro de di&amp;aacute;logo de formato definiremos &amp;eacute;ste sin decimales y con separador de miles.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_20.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_20.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una vez realizadas estas operaciones, la tabla din&amp;aacute;mica ya mostrar&amp;aacute; los datos de poblaci&amp;oacute;n de manera acorde a los requerimientos planteados.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_21.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201108/PiramidesPoblacionPowerPivot_5F00_21.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Llegados a este punto concluimos la primera parte del art&amp;iacute;culo. En la siguiente entrega alcanzaremos nuestro objetivo de crear un gr&amp;aacute;fico que represente la pir&amp;aacute;mide de poblaci&amp;oacute;n utilizando los datos que hemos preparado con PowerPivot.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=199678" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /><category term="PowerPivot" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/PowerPivot/default.aspx" /></entry><entry><title>Generación de datos demográficos desde SQL Server</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/07/18/generaci-243-n-de-datos-demogr-225-ficos-desde-sql-server.aspx" /><id>/blogs/lmblanco/archive/2011/07/18/generaci-243-n-de-datos-demogr-225-ficos-desde-sql-server.aspx</id><published>2011-07-18T20:25:00Z</published><updated>2011-07-18T20:25:00Z</updated><content type="html">&lt;p&gt;Con motivo de un pr&amp;oacute;ximo art&amp;iacute;culo que dedicaremos a la elaboraci&amp;oacute;n de pir&amp;aacute;mides de poblaci&amp;oacute;n desde PowerPivot, nos hemos encontrado recientemente ante la tesitura de desarrollar un proceso para crear una base de datos con informaci&amp;oacute;n demogr&amp;aacute;fica, que sirva como punto de partida para la construcci&amp;oacute;n del modelo de datos en PowerPivot.&lt;/p&gt;
&lt;p&gt;A diferencia del art&amp;iacute;culo &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/04/26/generar-datos-de-prueba-para-sql-server-desde-excel-operaciones-desde-excel-1.aspx"&gt;Generar datos de prueba para SQL Server desde Excel&lt;/a&gt;, publicado anteriormente en este mismo blog, donde utiliz&amp;aacute;bamos Excel para generar datos ficticios, tambi&amp;eacute;n de poblaci&amp;oacute;n, en esta ocasi&amp;oacute;n trabajaremos con datos reales, los cuales representan un mayor volumen de informaci&amp;oacute;n a manejar con respecto al mencionado art&amp;iacute;culo.&lt;/p&gt;
&lt;p&gt;El objetivo del presente art&amp;iacute;culo consistir&amp;aacute; en crear una base de datos que contenga una tabla de poblaci&amp;oacute;n, en la que cada registro represente a un individuo, con su correspondiente edad, sexo y zona de atenci&amp;oacute;n sanitaria.&lt;/p&gt;
&lt;p&gt;Antes de proseguir, quisiera expresar mi agradecimiento a Ricard G&amp;egrave;nova Maleras, dem&amp;oacute;grafo especializado en an&amp;aacute;lisis poblacionales sanitarios, perteneciente al Servicio de Informes de Salud y Estudios (Subdirecci&amp;oacute;n de Promoci&amp;oacute;n de la Salud y Prevenci&amp;oacute;n, DG Atenci&amp;oacute;n Primaria, Consejer&amp;iacute;a Sanidad CM), por su valioso asesoramiento en aquellos aspectos demogr&amp;aacute;ficos esenciales para la elaboraci&amp;oacute;n de &amp;eacute;ste y el pr&amp;oacute;ximo art&amp;iacute;culo sobre pir&amp;aacute;mides de poblaci&amp;oacute;n, as&amp;iacute; como al resto de integrantes del mencionado Servicio: Jenaro Astray Mochales, Mar&amp;iacute;a Felicitas Dom&amp;iacute;nguez Berj&amp;oacute;n, Mar&amp;iacute;a Dolores Esteban Vasallo y Beatriz Elvira Rodr&amp;iacute;guez, por su apoyo y ayuda en el resto de conceptos sanitarios relacionados con poblaciones, necesarios para el adecuado enfoque de este art&amp;iacute;culo.&lt;/p&gt;
&lt;p&gt;Por &amp;uacute;ltimo, aunque no menos importante, agradezco a Enrique Barcel&amp;oacute;, compa&amp;ntilde;ero de fatigas en estas labores del Business Intelligence, los interesantes ratos que pasamos departiendo acerca de los aspectos relacionados con el desarrollo de sistemas de informaci&amp;oacute;n en general, y sobre cubos de datos en particular, as&amp;iacute; como por compartir conmigo sus asombrosos conocimientos sobre OLAP.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Obtenci&amp;oacute;n y preparaci&amp;oacute;n de los datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Existe un importante n&amp;uacute;mero de sitios Web, pertenecientes a diversos organismos, donde encontraremos la informaci&amp;oacute;n demogr&amp;aacute;fica necesaria para realizar nuestros an&amp;aacute;lisis, organizada por criterios tales como sexo, edad, regi&amp;oacute;n geogr&amp;aacute;fica, etc. De todos estos organismos destacaremos los correspondientes a &lt;a href="http://esa.un.org/unpd/wpp/Excel-Data/population.htm"&gt;Naciones Unidas&lt;/a&gt;, &lt;a href="http://www.ine.es/inebmenu/mnu_cifraspob.htm"&gt;Instituto Nacional de Estad&amp;iacute;stica&lt;/a&gt; (Espa&amp;ntilde;a), &lt;a href="http://www.madrid.org/iestadis/fijas/estructu/demograficas/padron/estructupc.htm"&gt;Instituto de Estad&amp;iacute;stica de la CM&lt;/a&gt; (Madrid) y &lt;a href="http://www.eclac.org/celade/proyecciones/basedatos_BD.htm"&gt;CELADE&lt;/a&gt; (datos demogr&amp;aacute;ficos de Am&amp;eacute;rica Latina y Caribe). En todos ellos, adem&amp;aacute;s de la consulta directa en la propia web, disponemos de la posibilidad de descargar la informaci&amp;oacute;n en diversos formatos tales como Excel, CSV, etc.&lt;/p&gt;
&lt;p&gt;Para el desarrollo de los ejemplos de este art&amp;iacute;culo utilizaremos los datos del padr&amp;oacute;n de poblaci&amp;oacute;n de la Comunidad de Madrid correspondientes al a&amp;ntilde;o 2010, clasificados por edad, sexo y la nueva zonificaci&amp;oacute;n sanitaria, vigente a partir de dicho a&amp;ntilde;o, que se encuentran en el siguiente &lt;a href="http://www.madrid.org/iestadis/fijas/estructu/demograficas/padron/pc10i5z10.htm"&gt;enlace&lt;/a&gt; (T10Z2_SALUD10) de la p&amp;aacute;gina web del Instituto de Estad&amp;iacute;stica de la CM.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Estrategia para la extracci&amp;oacute;n de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;El archivo Excel pc10t10z2_salud10.xls, obtenido del anterior enlace, organiza los datos de poblaci&amp;oacute;n alrededor de tres hojas de c&amp;aacute;lculo que contienen, respectivamente, los valores de poblaci&amp;oacute;n totales, por hombres y mujeres.&lt;/p&gt;
&lt;p&gt;Cada hoja de c&amp;aacute;lculo tiene en sus dos primeras columnas el c&amp;oacute;digo y nombre de la zona de atenci&amp;oacute;n sanitaria, mientras que el resto de las columnas contienen las cifras de poblaci&amp;oacute;n clasificadas en agrupaciones quinquenales, donde para cada grupo existe una columna con el total quinquenal, y varias columnas que representan el desglose por edad simple de las edades que conforman el grupo.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_01.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_01.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Los datos que necesitamos extraer son, por un lado, los c&amp;oacute;digos y nombres de la zonificaci&amp;oacute;n sanitaria, para lo que podemos usar cualquiera de las hojas de c&amp;aacute;lculo del archivo Excel. Por otra parte, tendremos que obtener el total quinquenal de cada grupo de edad, tanto de la hoja de poblaci&amp;oacute;n masculina como femenina.&lt;/p&gt;
&lt;p&gt;Todos estos valores los llevaremos a una nueva hoja de c&amp;aacute;lculo en la que copiaremos cada combinaci&amp;oacute;n de c&amp;oacute;digos de zona sanitaria, grupo de edad y tipo de poblaci&amp;oacute;n (hombre/mujer) siguiendo un orden de pasos parecido al de la siguiente figura.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_02.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_02.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n observamos una aproximaci&amp;oacute;n de lo que ser&amp;iacute;a la hoja de c&amp;aacute;lculo resultante.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_03.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_03.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El empleo manual de las operaciones seleccionar, copiar y pegar, para traspasar los datos que necesitamos a una nueva hoja puede resultar una tarea muy laboriosa y pesada. Es por ello que proponemos el uso de una macro que automatice toda esta labor, lo que nos permitir&amp;aacute; repetir el proceso cuantas veces queramos, as&amp;iacute; como aplicarlo a otras poblaciones cuyos datos se encuentren estructurados de la misma forma.&lt;/p&gt;
&lt;p&gt;Para crear la macro, en la cinta de opciones de Excel haremos clic en la opci&amp;oacute;n &amp;quot;Macros&amp;quot;, perteneciente al grupo del mismo nombre situado en la ficha &amp;quot;Vista&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_04.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_04.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esta opci&amp;oacute;n tambi&amp;eacute;n est&amp;aacute; disponible en la ficha &amp;quot;Programador&amp;quot; dentro del grupo &amp;quot;C&amp;oacute;digo&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_05.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_05.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;En el caso de que la ficha &amp;quot;Programador&amp;quot; no est&amp;eacute; visible haremos clic en la ficha &amp;quot;Archivo&amp;quot;, y dentro de esta en &amp;quot;Opciones&amp;quot;. En la ventana &amp;quot;Opciones de Excel&amp;quot; haremos clic en &amp;quot;Personalizar cinta de opciones&amp;quot;, y desplegando la lista situada a la derecha seleccionaremos el elemento &amp;quot;Fichas principales&amp;quot;. Del panel situado debajo de la lista marcaremos la casilla &amp;quot;Programador&amp;quot;, lo que har&amp;aacute; visible esta ficha en la cinta de opciones.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_06.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_06.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Independientemente del modo elegido para su creaci&amp;oacute;n, aparecer&amp;aacute; la ventana &amp;quot;Macro&amp;quot;, en la que daremos el nombre &amp;quot;TraspasarDatosPoblacion&amp;quot; a nuestra macro y haremos clic en &amp;quot;Crear&amp;quot;, lo que nos llevar&amp;aacute; al editor de VBA (Visual Basic for Applications), donde escribiremos el c&amp;oacute;digo de la macro.&lt;/p&gt;
&lt;p&gt;Vamos a dividir el trabajo que realizar&amp;aacute; la macro en tres partes: la creaci&amp;oacute;n de los datos para la columna de c&amp;oacute;digos de zona sanitaria; la columna de rangos de edad; y por &amp;uacute;ltimo, las columnas de cantidades de poblaci&amp;oacute;n por sexo.&lt;/p&gt;
&lt;p&gt;En el siguiente bloque de c&amp;oacute;digo podemos ver las instrucciones encargadas de crear una nueva hoja de c&amp;aacute;lculo, a la que asignaremos un nombre y los t&amp;iacute;tulos de columna. Posteriormente seleccionaremos los c&amp;oacute;digos de zona de una de las hojas origen, que pegaremos en la nueva hoja tantas veces como rangos de edad existan.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;Option&lt;/span&gt; Explicit&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Const&lt;/span&gt; RANGOS_COLUMNAS &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Integer&lt;/span&gt; = 20&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Sub&lt;/span&gt; TraspasarDatosPoblacion()&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; crear nueva hoja y asignarle nombre&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sHojaDestino &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;sHojaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;DatosBasePoblacion&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; oWorksheet &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; Worksheet&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Set&lt;/span&gt; oWorksheet = Sheets.Add(After:=Sheets(Sheets.Count))&lt;br /&gt;oWorksheet.Name = sHojaDestino&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; asignar t&amp;iacute;tulos en columnas&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Zona&amp;quot;&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;B1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Rango_Edad&amp;quot;&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;C1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Poblacion_H&amp;quot;&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;D1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Poblacion_M&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; volver a la hoja de datos origen&lt;/span&gt;&lt;br /&gt;Sheets(&lt;span style="color:#006080;"&gt;&amp;quot;Hombres&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; establecer fila inicial y final de datos&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sFilaInicial &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sFilaFinal &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;sFilaInicial = &lt;span style="color:#006080;"&gt;&amp;quot;14&amp;quot;&lt;/span&gt;&lt;br /&gt;sFilaFinal = &lt;span style="color:#006080;"&gt;&amp;quot;299&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; calcular cantidad de zonas existentes&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; nCantidadZonas &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Integer&lt;/span&gt;&lt;br /&gt;nCantidadZonas = (&lt;span style="color:#0000ff;"&gt;CInt&lt;/span&gt;(sFilaFinal) - &lt;span style="color:#0000ff;"&gt;CInt&lt;/span&gt;(sFilaInicial))&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; c&amp;oacute;digos de zona&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; ---------------&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sColumna &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;sColumna = &lt;span style="color:#006080;"&gt;&amp;quot;A&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; seleccionar c&amp;oacute;digos, copiarlos al portapapeles y pegarlos en nueva hoja&lt;/span&gt;&lt;br /&gt;Range(sColumna &amp;amp; sFilaInicial &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sColumna &amp;amp; sFilaFinal).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.Copy&lt;br /&gt;Sheets(sHojaDestino).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; nContador &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; nFilaVacia &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Long&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; realizar el pegado por cada grupo de edad&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;For&lt;/span&gt; nContador = 0 &lt;span style="color:#0000ff;"&gt;To&lt;/span&gt; RANGOS_COLUMNAS&lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; obtener el siguiente n&amp;uacute;mero de fila vac&amp;iacute;o de la columna&lt;/span&gt;&lt;br /&gt;    nFilaVacia = FilaVaciaEnColumna(1)&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; posicionar en celda&lt;/span&gt;&lt;br /&gt;    Range(sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia)).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; pegar datos&lt;/span&gt;&lt;br /&gt;    ActiveSheet.Paste&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Next&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; asignar fondo color blanco a columna&lt;/span&gt;&lt;br /&gt;Columns(&lt;span style="color:#006080;"&gt;&amp;quot;A:A&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.Interior.Pattern = xlNone&lt;br /&gt;Selection.Interior.TintAndShade = 0&lt;br /&gt;Selection.Interior.PatternTintAndShade = 0&lt;br /&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Antes de cada operaci&amp;oacute;n de asignaci&amp;oacute;n de valores en las celdas, necesitamos conocer la fila vac&amp;iacute;a a partir de la que pegaremos los datos, para lo que utilizaremos la funci&amp;oacute;n auxiliar &amp;quot;FilaVaciaEnColumna&amp;quot;, que recorrer&amp;aacute; la colecci&amp;oacute;n de filas de la hoja hasta encontrar la fila que contiene una celda vac&amp;iacute;a en aquella columna sobre la que estamos operando.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;Function&lt;/span&gt; FilaVaciaEnColumna(&lt;span style="color:#0000ff;"&gt;ByVal&lt;/span&gt; nPosicionCelda &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Integer&lt;/span&gt;) &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Long&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; vFila &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Variant&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; nFila &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Long&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;For&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Each&lt;/span&gt; vFila &lt;span style="color:#0000ff;"&gt;In&lt;/span&gt; ActiveSheet.Rows&lt;br /&gt;    nFila = vFila.Row&lt;br /&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;If&lt;/span&gt; vFila.Cells(nPosicionCelda).Text = &lt;span style="color:#006080;"&gt;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Then&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;Exit&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;For&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;End&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;If&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Next&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;FilaVaciaEnColumna = nFila&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;End&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Function&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;La siguiente fase en la creaci&amp;oacute;n de la macro consistir&amp;aacute; en asignar los valores a la columna de rangos de edad. Para ello crearemos un array conteniendo dichos valores, y al recorrerlo, haremos que en cada iteraci&amp;oacute;n se copie el valor del rango en curso el mismo n&amp;uacute;mero de veces que la cantidad de zonas sanitarias existentes. Cabe destacar que antes de asignar los valores a esta columna le aplicaremos el formato texto (propiedad Selection.NumberFormat), ya que en caso contrario, el formato predeterminado puede hacer que algunos valores de los rangos de edad sean interpretados como mes-a&amp;ntilde;o.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39; rangos de edad&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; --------------&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; aRangosEdad(RANGOS_COLUMNAS) &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;aRangosEdad(0) = &lt;span style="color:#006080;"&gt;&amp;quot;0-4&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(1) = &lt;span style="color:#006080;"&gt;&amp;quot;5-9&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(2) = &lt;span style="color:#006080;"&gt;&amp;quot;10-14&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(3) = &lt;span style="color:#006080;"&gt;&amp;quot;15-19&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(4) = &lt;span style="color:#006080;"&gt;&amp;quot;20-24&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(5) = &lt;span style="color:#006080;"&gt;&amp;quot;25-29&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(6) = &lt;span style="color:#006080;"&gt;&amp;quot;30-34&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(7) = &lt;span style="color:#006080;"&gt;&amp;quot;35-39&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(8) = &lt;span style="color:#006080;"&gt;&amp;quot;40-44&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(9) = &lt;span style="color:#006080;"&gt;&amp;quot;45-49&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(10) = &lt;span style="color:#006080;"&gt;&amp;quot;50-54&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(11) = &lt;span style="color:#006080;"&gt;&amp;quot;55-59&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(12) = &lt;span style="color:#006080;"&gt;&amp;quot;60-64&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(13) = &lt;span style="color:#006080;"&gt;&amp;quot;65-69&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(14) = &lt;span style="color:#006080;"&gt;&amp;quot;70-74&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(15) = &lt;span style="color:#006080;"&gt;&amp;quot;75-79&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(16) = &lt;span style="color:#006080;"&gt;&amp;quot;80-84&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(17) = &lt;span style="color:#006080;"&gt;&amp;quot;85-89&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(18) = &lt;span style="color:#006080;"&gt;&amp;quot;90-94&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(19) = &lt;span style="color:#006080;"&gt;&amp;quot;95-99&amp;quot;&lt;/span&gt;&lt;br /&gt;aRangosEdad(20) = &lt;span style="color:#006080;"&gt;&amp;quot;100+&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; establecer el formato de la columna de edad a texto&lt;/span&gt;&lt;br /&gt;sColumna = &lt;span style="color:#006080;"&gt;&amp;quot;B&amp;quot;&lt;/span&gt;&lt;br /&gt;Columns(sColumna &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sColumna).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.NumberFormat = &lt;span style="color:#006080;"&gt;&amp;quot;@&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; repetir cada valor del array aRangosEdad&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; tantas veces como n&amp;uacute;mero de zonas existen&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; vRangoEdad &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Variant&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;For&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Each&lt;/span&gt; vRangoEdad &lt;span style="color:#0000ff;"&gt;In&lt;/span&gt; aRangosEdad&lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; obtener el siguiente n&amp;uacute;mero de fila vac&amp;iacute;o de la columna&lt;/span&gt;&lt;br /&gt;    nFilaVacia = FilaVaciaEnColumna(2)&lt;br /&gt; &lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; asignar el valor del rango de edad en las dos siguientes celdas hacia abajo&lt;/span&gt;&lt;br /&gt;    Range(sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia)).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;    ActiveCell.FormulaR1C1 = vRangoEdad&lt;br /&gt;     &lt;br /&gt;    Range(sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia + 1)).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;    ActiveCell.FormulaR1C1 = vRangoEdad&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; establecer el rango de celdas y rellenar con el valor de las anteriores celdas&lt;/span&gt;&lt;br /&gt;    Range(sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia) &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia + 1)).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;    Selection.AutoFill Destination:=Range(sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia) &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia + nCantidadZonas)), Type:=xlFillDefault&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Y terminaremos la macro con la asignaci&amp;oacute;n de las columnas dedicadas a las cifras de poblaci&amp;oacute;n por sexo, donde esta vez utilizaremos dos arrays combinados, conteniendo las cabeceras de columna que corresponden a los totales quinquenales de poblaci&amp;oacute;n, y el tipo de poblaci&amp;oacute;n. Al recorrer ambos de forma anidada, iremos extrayendo, para un tipo de poblaci&amp;oacute;n determinado, sus cifras de individuos, asign&amp;aacute;ndolas a la hoja de c&amp;aacute;lculo destino.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39; cifras de poblaci&amp;oacute;n por sexo&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; ----------------------------&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; aColumnasPoblacion(RANGOS_COLUMNAS) &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(0) = &lt;span style="color:#006080;"&gt;&amp;quot;D&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(1) = &lt;span style="color:#006080;"&gt;&amp;quot;J&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(2) = &lt;span style="color:#006080;"&gt;&amp;quot;P&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(3) = &lt;span style="color:#006080;"&gt;&amp;quot;V&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(4) = &lt;span style="color:#006080;"&gt;&amp;quot;AB&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(5) = &lt;span style="color:#006080;"&gt;&amp;quot;AH&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(6) = &lt;span style="color:#006080;"&gt;&amp;quot;AN&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(7) = &lt;span style="color:#006080;"&gt;&amp;quot;AT&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(8) = &lt;span style="color:#006080;"&gt;&amp;quot;AZ&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(9) = &lt;span style="color:#006080;"&gt;&amp;quot;BF&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(10) = &lt;span style="color:#006080;"&gt;&amp;quot;BL&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(11) = &lt;span style="color:#006080;"&gt;&amp;quot;BR&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(12) = &lt;span style="color:#006080;"&gt;&amp;quot;BX&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(13) = &lt;span style="color:#006080;"&gt;&amp;quot;CD&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(14) = &lt;span style="color:#006080;"&gt;&amp;quot;CJ&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(15) = &lt;span style="color:#006080;"&gt;&amp;quot;CP&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(16) = &lt;span style="color:#006080;"&gt;&amp;quot;CV&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(17) = &lt;span style="color:#006080;"&gt;&amp;quot;DB&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(18) = &lt;span style="color:#006080;"&gt;&amp;quot;DH&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(19) = &lt;span style="color:#006080;"&gt;&amp;quot;DN&amp;quot;&lt;/span&gt;&lt;br /&gt;aColumnasPoblacion(20) = &lt;span style="color:#006080;"&gt;&amp;quot;DT&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; aTiposPoblacionColumnas(1) &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;aTiposPoblacionColumnas(0) = &lt;span style="color:#006080;"&gt;&amp;quot;Hombres,C,3&amp;quot;&lt;/span&gt;&lt;br /&gt;aTiposPoblacionColumnas(1) = &lt;span style="color:#006080;"&gt;&amp;quot;Mujeres,D,4&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; vTipoPoblacionColumna &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Variant&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sTipoPoblacion &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; nPosicionColumna &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Integer&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; vColumnaPoblacion &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Variant&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; por cada tipo de poblaci&amp;oacute;n&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;For&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Each&lt;/span&gt; vTipoPoblacionColumna &lt;span style="color:#0000ff;"&gt;In&lt;/span&gt; aTiposPoblacionColumnas&lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; obtener la informaci&amp;oacute;n del tipo de poblaci&amp;oacute;n:&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; sexo, columna destino, posici&amp;oacute;n num&amp;eacute;rica columna destino&lt;/span&gt;&lt;br /&gt;    sTipoPoblacion = Split(vTipoPoblacionColumna, &lt;span style="color:#006080;"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;)(0)&lt;br /&gt;    sColumna = Split(vTipoPoblacionColumna, &lt;span style="color:#006080;"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;)(1)&lt;br /&gt;    nPosicionColumna = Split(vTipoPoblacionColumna, &lt;span style="color:#006080;"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;)(2)&lt;br /&gt; &lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; recorrer las columnas que contienen las cifras de poblaci&amp;oacute;n&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#008000;"&gt;&amp;#39; y pegarlas en la nueva hoja&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;For&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Each&lt;/span&gt; vColumnaPoblacion &lt;span style="color:#0000ff;"&gt;In&lt;/span&gt; aColumnasPoblacion&lt;br /&gt;        &lt;span style="color:#008000;"&gt;&amp;#39; posicionar en hoja con datos origen poblaci&amp;oacute;n&lt;/span&gt;&lt;br /&gt;        Sheets(sTipoPoblacion).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;     &lt;br /&gt;        &lt;span style="color:#008000;"&gt;&amp;#39; seleccionar celdas y copiarlas&lt;/span&gt;&lt;br /&gt;        Range(vColumnaPoblacion &amp;amp; sFilaInicial &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; vColumnaPoblacion &amp;amp; sFilaFinal).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;        Selection.Copy&lt;br /&gt;         &lt;br /&gt;        &lt;span style="color:#008000;"&gt;&amp;#39; posicionar en hoja destino de los datos&lt;/span&gt;&lt;br /&gt;        Sheets(sHojaDestino).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;        &lt;span style="color:#008000;"&gt;&amp;#39; obtener siguiente fila vac&amp;iacute;a, posicionar en celda y pegar los datos&lt;/span&gt;&lt;br /&gt;        nFilaVacia = FilaVaciaEnColumna(nPosicionColumna)&lt;br /&gt;        Range(sColumna &amp;amp; &lt;span style="color:#0000ff;"&gt;CStr&lt;/span&gt;(nFilaVacia)).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;        ActiveSheet.Paste&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;Next&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Next&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; cambiar estilo de columnas para que se visualicen bordes de celdas&lt;/span&gt;&lt;br /&gt;Columns(&lt;span style="color:#006080;"&gt;&amp;quot;C:D&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.Style = &lt;span style="color:#006080;"&gt;&amp;quot;Normal&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;End&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Seguidamente crearemos una nueva macro con el nombre &amp;quot;TraspasarDatosZonificacion&amp;quot;, que trasladar&amp;aacute; a una nueva hoja del archivo Excel los c&amp;oacute;digos y nombres de las zonas de asistencia sanitaria. Estos datos servir&amp;aacute;n para cargar una de las tablas cat&amp;aacute;logo de la base de datos que crearemos m&amp;aacute;s adelante.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;Sub&lt;/span&gt; TraspasarDatosZonificacion()&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; crear nueva hoja y asignarle nombre&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sHojaDestino &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;sHojaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;DatosZonificacion&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; oWorksheet &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; Worksheet&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Set&lt;/span&gt; oWorksheet = Sheets.Add(After:=Sheets(Sheets.Count))&lt;br /&gt;oWorksheet.Name = sHojaDestino&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; poner t&amp;iacute;tulos de columna&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Zona_ID&amp;quot;&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;B1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Zona_DS&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; volver a la hoja de datos&lt;/span&gt;&lt;br /&gt;Sheets(&lt;span style="color:#006080;"&gt;&amp;quot;Hombres&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; copiar c&amp;oacute;digos y nombres de zonas al portapapeles&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A14:B299&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.Copy&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; volver a hoja destino y pegar los datos&lt;/span&gt;&lt;br /&gt;Sheets(sHojaDestino).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A2&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveSheet.Paste&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39; quitar color de fondo de celdas&lt;/span&gt;&lt;br /&gt;Columns(&lt;span style="color:#006080;"&gt;&amp;quot;A:B&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.Interior.Pattern = xlNone&lt;br /&gt;Selection.Interior.TintAndShade = 0&lt;br /&gt;Selection.Interior.PatternTintAndShade = 0&lt;br /&gt; &lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;End&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Cuando copiamos los c&amp;oacute;digos y nombres de las zonas sanitarias a las nuevas hojas dentro del archivo Excel, tambi&amp;eacute;n se copia la configuraci&amp;oacute;n de colores de las celdas correspondientes a estos valores. Para conseguir que el color de fondo de estas celdas sea blanco utilizamos las siguientes l&amp;iacute;neas de c&amp;oacute;digo.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;Selection.Interior.TintAndShade = 0&lt;br /&gt;Selection.Interior.PatternTintAndShade = 0&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Pero si nuestra versi&amp;oacute;n de Excel es anterior a 2007 estas l&amp;iacute;neas producir&amp;aacute;n un error en tiempo de ejecuci&amp;oacute;n, por lo que deberemos comentarlas para evitar que sean ejecutadas.&lt;/p&gt;
&lt;p&gt;Finalmente, desde la ventana de administraci&amp;oacute;n de macros, seleccionaremos cada una y haremos clic en &amp;quot;Ejecutar&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_07.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_07.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Como resultado obtendremos dos nuevas hojas con los datos generados por el c&amp;oacute;digo de las macros.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_08.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_08.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creaci&amp;oacute;n de la base de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Nuestro pr&amp;oacute;ximo paso consistir&amp;aacute; en crear la base de datos PiramidePoblacion, que alojar&amp;aacute; la informaci&amp;oacute;n que acabamos de preparar en Excel. El siguiente bloque de c&amp;oacute;digo muestra el script de Transact-SQL que tendremos que ejecutar en nuestra instancia de SQL Server (la versi&amp;oacute;n utilizada en este art&amp;iacute;culo ha sido SQL Server 2008 R2).&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DATABASE&lt;/span&gt; PiramidePoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;USE&lt;/span&gt; PiramidePoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; DatosBasePoblacion&lt;br /&gt;(&lt;br /&gt;    Fila_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Zona &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(3) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Rango_Edad &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(10) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Poblacion_H &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Poblacion_M &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;&lt;br /&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Poblacion&lt;br /&gt;(&lt;br /&gt;    Fila_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;IDENTITY&lt;/span&gt;(1,1) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Zona_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(3) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Edad_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Sexo_ID &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(1) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;             &lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Poblacion &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Fila_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;)&lt;br /&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Zona&lt;br /&gt;(&lt;br /&gt;    Zona_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(3) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Zona_DS &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(30) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;             &lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Zona &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Zona_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;)&lt;br /&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Edad&lt;br /&gt;(&lt;br /&gt;    Edad_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Edad_Grupo &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;             &lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Edad &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Edad_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;)&lt;br /&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Sexo&lt;br /&gt;(&lt;br /&gt;    Sexo_ID &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(1) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;    Sexo_DS &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(10) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;             &lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Sexo &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Sexo_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;)&lt;br /&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;La tabla Poblaci&amp;oacute;n, como podemos adivinar por su nombre, ser&amp;aacute; la que contenga los datos principales de nuestra poblaci&amp;oacute;n, mientras que las tablas Zona, Edad y Sexo contendr&amp;aacute;n informaci&amp;oacute;n de cat&amp;aacute;logo (c&amp;oacute;digo/descriptor).&lt;/p&gt;
&lt;p&gt;Con toda seguridad, en el script habremos notado la carencia de claves ajenas entre la tabla Poblaci&amp;oacute;n y el resto. Se trata de un olvido intencionado, ya que en el pr&amp;oacute;ximo art&amp;iacute;culo sobre pir&amp;aacute;mides de poblaci&amp;oacute;n esto nos servir&amp;aacute; para demostrar c&amp;oacute;mo a trav&amp;eacute;s de PowerPivot tambi&amp;eacute;n es posible crear relaciones entre las tablas del modelo.&lt;/p&gt;
&lt;p&gt;Despu&amp;eacute;s de ejecutar el script, la primera acci&amp;oacute;n que realizaremos en la nueva base de datos ser&amp;aacute; el volcado, desde el archivo pc10t10z2_salud10.xls, de la hoja de c&amp;aacute;lculo DatosBasePoblacion en la tabla del mismo nombre, utilizando la siguiente sentencia.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; DatosBasePoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; * &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;OPENROWSET&lt;/span&gt;(&lt;span style="color:#006080;"&gt;&amp;#39;Microsoft.ACE.OLEDB.12.0&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;Excel 8.0;Database=C:\DatosOrigen\pc10t10z2_salud10.xls&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;SELECT * FROM [DatosBasePoblacion$]&amp;#39;&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;&lt;b&gt;Generando los registros de poblaci&amp;oacute;n en la base de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;La finalidad del proceso que estamos llevando a cabo hasta este momento consiste en generar, para la tabla Poblaci&amp;oacute;n, una cantidad de registros que represente a la poblaci&amp;oacute;n con la que vamos a trabajar, y que ser&amp;aacute; igual a la suma de las columnas Poblacion_H y Poblacion_M de la tabla DatosBasePoblacion.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_09.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201107/GeneracionDatosDemograficosSQLServer_5F00_09.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para tal volumen de datos, el uso de un bucle que vaya creando uno a uno los registros resulta totalmente inviable por cuestiones de tiempo y rendimiento, por lo que debemos buscar un sistema alternativo, que nos permita trabajar utilizando conjuntos de resultados, para poder crear la cantidad de registros que necesitamos empleando un reducido n&amp;uacute;mero de operaciones.&lt;/p&gt;
&lt;p&gt;La t&amp;eacute;cnica por la que vamos a decantarnos se muestra en el libro &lt;a href="http://www.microsoft.com/learning/en/us/book.aspx?ID=12804&amp;amp;locale=en-us"&gt;Microsoft SQL Server 2008: T-SQL Querying&lt;/a&gt;, escrito por &lt;a href="http://tsql.solidq.com/index.htm"&gt;Itzik Ben-Gan&lt;/a&gt; junto a otros grandes nombres de SQL Server: Lubor Kollar, Dejan Sarka y Steve Kass; y consiste en utilizar varias &amp;quot;Expresiones Comunes de Tabla&amp;quot; o CTE (Common Table Expression) anidadas, mediante las cuales generaremos un conjunto de resultados del tama&amp;ntilde;o necesario, que combinaremos con una sentencia INSERT INTO, para a&amp;ntilde;adir a la tabla Poblaci&amp;oacute;n un n&amp;uacute;mero de registros determinado. Todo ello lo incluiremos en el siguiente procedimiento almacenado.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;PROCEDURE&lt;/span&gt; GenerarRegistrosPoblacion&lt;br /&gt;@sZona_ID &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(3),&lt;br /&gt;@sRango_Edad &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(10),&lt;br /&gt;@sSexo_ID &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(1),&lt;br /&gt;@nPoblacion &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nEdad_ID &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; =&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;CASE&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; CHARINDEX(&lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;,@sRango_Edad) = 0 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; 100&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; CHARINDEX(&lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;,@sRango_Edad) = 2 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CAST&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;LEFT&lt;/span&gt;(@sRango_Edad,1) &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; CHARINDEX(&lt;span style="color:#006080;"&gt;&amp;#39;-&amp;#39;&lt;/span&gt;,@sRango_Edad) = 3 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CAST&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;LEFT&lt;/span&gt;(@sRango_Edad,2) &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt;&lt;br /&gt;Numeros0 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; Numero &lt;span style="color:#0000ff;"&gt;UNION&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;ALL&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1),&lt;br /&gt;Numeros1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; Numero &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Numeros0 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblPrim &lt;span style="color:#0000ff;"&gt;CROSS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Numeros0 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblSeg),&lt;br /&gt;Numeros2 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; Numero &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Numeros1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblPrim &lt;span style="color:#0000ff;"&gt;CROSS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Numeros1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblSeg),&lt;br /&gt;Numeros3 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; Numero &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Numeros2 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblPrim &lt;span style="color:#0000ff;"&gt;CROSS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Numeros2 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblSeg),&lt;br /&gt;Numeros4 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; Numero &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Numeros3 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblPrim &lt;span style="color:#0000ff;"&gt;CROSS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Numeros3 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblSeg),&lt;br /&gt;Numeros5 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 1 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; Numero &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Numeros4 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblPrim &lt;span style="color:#0000ff;"&gt;CROSS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;JOIN&lt;/span&gt; Numeros4 &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; TblSeg),&lt;br /&gt;NumerosTotal &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; ROW_NUMBER() &lt;span style="color:#0000ff;"&gt;OVER&lt;/span&gt;(&lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; 0)) &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; NumeroFila &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Numeros5)&lt;br /&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Poblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @sZona_ID, @nEdad_ID, @sSexo_ID &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; NumerosTotal&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; NumeroFila &amp;lt;= @nPoblacion;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;GO&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;A continuaci&amp;oacute;n escribiremos un script en el que recorreremos la tabla DatosBasePoblacion, y por cada uno de sus registros tomaremos el valor de los campos Poblacion_H y Poblacion_M, insertando en la tabla Poblaci&amp;oacute;n, mediante la ejecuci&amp;oacute;n del procedimiento almacenado GenerarRegistrosPoblacion, un n&amp;uacute;mero de filas igual al valor de los mencionados campos.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; = 1;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nDatosBaseFilaFinal &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; = (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;MAX&lt;/span&gt;(Fila_ID) &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; DatosBasePoblacion);&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @sZona &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(3);&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @sRango_Edad &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(10);&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nPoblacion_H &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nPoblacion_M &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;;&lt;br /&gt; &lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WHILE&lt;/span&gt; (@nContador &amp;lt;= @nDatosBaseFilaFinal)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @sZona = Zona,&lt;br /&gt;        @sRango_Edad = Rango_Edad,&lt;br /&gt;        @nPoblacion_H = Poblacion_H, &lt;br /&gt;        @nPoblacion_M = Poblacion_M&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; DatosBasePoblacion&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; Fila_ID = @nContador;&lt;br /&gt; &lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;EXECUTE&lt;/span&gt; GenerarRegistrosPoblacion @sZona, @sRango_Edad, &lt;span style="color:#006080;"&gt;&amp;#39;H&amp;#39;&lt;/span&gt;, @nPoblacion_H&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;EXECUTE&lt;/span&gt; GenerarRegistrosPoblacion @sZona, @sRango_Edad, &lt;span style="color:#006080;"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;, @nPoblacion_M&lt;br /&gt;    &lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @nContador += 1&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;El tiempo empleado en la ejecuci&amp;oacute;n de este script ha sido de 1 minuto y 37 segundos en una m&amp;aacute;quina virtual dotada de una CPU Core 2 Duo y 1,5 GB de RAM, lo cual representa un excelente rendimiento, dado el elevado n&amp;uacute;mero de registros a&amp;ntilde;adidos a la tabla Poblaci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Terminamos las operaciones de preparaci&amp;oacute;n de la base de datos con las sentencias utilizadas para a&amp;ntilde;adir datos en las tablas que actuar&amp;aacute;n como cat&amp;aacute;logos de la tabla Poblaci&amp;oacute;n. Como vemos a continuaci&amp;oacute;n, para la tabla Zona tambi&amp;eacute;n obtenemos los registros del archivo pc10t10z2_salud10.xls.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;--&lt;span style="color:#008000;"&gt;////&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;INSERT INTO&lt;/span&gt; Zona&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; * &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;OPENROWSET&lt;/span&gt;(&lt;span style="color:#006080;"&gt;&amp;#39;Microsoft.ACE.OLEDB.12.0&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;Excel 8.0;Database=C:\DatosOrigen\pc10t10z2_salud10.xls&amp;#39;&lt;/span&gt;, &lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;SELECT * FROM [DatosZonificacion$]&amp;#39;&lt;/span&gt;)&lt;br /&gt; &lt;br /&gt;--&lt;span style="color:#008000;"&gt;////&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;DECLARE&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; = 0;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WHILE&lt;/span&gt; (@nContador &amp;lt;= 120)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;INSERT &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Edad&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; @nContador,&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;CASE&lt;/span&gt; &lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 0 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 4 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;000-004&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 5 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 9 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;005-009&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 10 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 14 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;010-014&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 15 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 19 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;015-019&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 20 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 24 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;020-024&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 25 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 29 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;025-029&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 30 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 34 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;030-034&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 35 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 39 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;035-039&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 40 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 44 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;040-044&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 45 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 49 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;045-049&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 50 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 54 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;050-054&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 55 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 59 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;055-059&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 60 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 64 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;060-064&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 65 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 69 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;065-069&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 70 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 74 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;070-074&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 75 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 79 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;075-079&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 80 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 84 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;080-084&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 85 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 89 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;085-089&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 90 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 94 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;090-094&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &lt;span style="color:#0000ff;"&gt;BETWEEN&lt;/span&gt; 95 &lt;span style="color:#0000ff;"&gt;AND&lt;/span&gt; 99 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;095-099&amp;#39;&lt;/span&gt;&lt;br /&gt;            &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; @nContador &amp;gt;= 100 &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;100+&amp;#39;&lt;/span&gt;&lt;br /&gt;        &lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @nContador += 1;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;--&lt;span style="color:#008000;"&gt;////&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;INSERT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Sexo &lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;H&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Hombre&amp;#39;&lt;/span&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;INSERT &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Sexo &lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Mujer&amp;#39;&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Carga de datos completada&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Llegados a este punto podemos dar por finalizado el proceso de creaci&amp;oacute;n y carga de informaci&amp;oacute;n demogr&amp;aacute;fica en nuestra base de datos. Como hemos comentado al comienzo, en un pr&amp;oacute;ximo art&amp;iacute;culo utilizaremos esta base de datos como punto de partida para la construcci&amp;oacute;n de pir&amp;aacute;mides de poblaci&amp;oacute;n con PowerPivot.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=197962" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /></entry><entry><title>Generar datos de prueba para SQL Server desde Excel. El traspaso a SQL Server (y 2)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/04/28/generar-datos-de-prueba-para-sql-server-desde-excel-el-traspaso-a-sql-server-y-2.aspx" /><id>/blogs/lmblanco/archive/2011/04/28/generar-datos-de-prueba-para-sql-server-desde-excel-el-traspaso-a-sql-server-y-2.aspx</id><published>2011-04-28T18:30:00Z</published><updated>2011-04-28T18:30:00Z</updated><content type="html">&lt;p&gt;Despu&amp;eacute;s de la generaci&amp;oacute;n de datos realizada en Excel, que explicamos en la primera parte del art&amp;iacute;culo, en esta segunda entrega trataremos acerca de la forma de insertar dicha informaci&amp;oacute;n en una base de datos SQL Server.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creaci&amp;oacute;n de la base de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Finalizada la creaci&amp;oacute;n de la hoja de c&amp;aacute;lculo, volcaremos su contenido en una base de datos SQL Server, que crearemos a continuaci&amp;oacute;n ejecutando el siguiente script desde SQL Server Management Studio.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;USE&lt;/span&gt; master&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DATABASE&lt;/span&gt; Poblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;USE&lt;/span&gt; Poblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; DatosPoblacion (&lt;br /&gt;Fila_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Edad_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Sexo_ID &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(1) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;CCAA_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Pais_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Fecha_Alta datetime &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_DatosPoblacion &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Fila_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;))&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Sexo (&lt;br /&gt;Sexo_ID &lt;span style="color:#0000ff;"&gt;char&lt;/span&gt;(1) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Sexo_DS &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(10) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Sexo &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Sexo_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;))&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; CCAA (&lt;br /&gt;CCAA_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;CCAA_DS &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(50) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_CCAA &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (CCAA_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;))&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Pais (&lt;br /&gt;Pais_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Pais_DS &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(50) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Paises &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (Pais_ID &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;))&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Como acabamos de comprobar, adem&amp;aacute;s de la tabla que albergar&amp;aacute; los datos que generamos desde Excel, tambi&amp;eacute;n crearemos las tablas cat&amp;aacute;logo, que contendr&amp;aacute;n las descripciones de ciertos campos de c&amp;oacute;digo existentes en la tabla DatosPoblacion, con las que estableceremos las oportunas relaciones.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_13.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_13.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Importar los datos de Excel desde SQL Server&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para insertar datos en la tabla DatosPoblacion de SQL Server, utilizaremos la funci&amp;oacute;n OPENROWSET de Transact-SQL de la siguiente manera.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; DatosPoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; Fila_ID,Edad_ID,Sexo_ID,CCAA_ID,Pais_ID,Fecha_Alta&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;OPENROWSET&lt;/span&gt;(&lt;span style="color:#006080;"&gt;&amp;#39;Microsoft.ACE.OLEDB.12.0&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;Excel 8.0;Database=C:\DatosOrigen\GenerarDatosPoblacion.xlsx&amp;#39;&lt;/span&gt;, &lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;SELECT * FROM [Hoja1$]&amp;#39;&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Sin embargo, es posible que al intentar ejecutar esta sentencia de inserci&amp;oacute;n, nos encontremos con un error, que nos informa de que SQL Server no est&amp;aacute; configurado para realizar consultas de estas caracter&amp;iacute;sticas, denominadas &amp;#39;Ad Hoc Distributed Queries&amp;#39;.&lt;/p&gt;
&lt;p&gt;Si queremos comprobar la configuraci&amp;oacute;n de opciones de SQL Server, debemos ejecutar el procedimiento almacenado de sistema sp_configure. No obstante, lo m&amp;aacute;s probable es que entre las opciones mostradas, no veamos la configuraci&amp;oacute;n de consultas distribuidas. Si estamos en este caso, tenemos que activar la visualizaci&amp;oacute;n de opciones avanzadas utilizando las siguientes sentencias.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;EXECUTE&lt;/span&gt; sp_configure &lt;span style="color:#006080;"&gt;&amp;#39;show advanced options&amp;#39;&lt;/span&gt;,1&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;RECONFIGURE&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Ahora ya podremos ver el valor de la opci&amp;oacute;n &amp;#39;Ad Hoc Distributed Queries&amp;#39; al ejecutar sp_configure. Para activarlo ejecutaremos lo siguiente.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;EXECUTE&lt;/span&gt; sp_configure &lt;span style="color:#006080;"&gt;&amp;#39;Ad Hoc Distributed Queries&amp;#39;&lt;/span&gt;,1&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;RECONFIGURE&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Al volver al ejecutar sp_configure, veremos que ya est&amp;aacute; activada la posibilidad de ejecutar consultas distribuidas.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_14.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_14.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;De esta forma, la anterior sentencia con OPENROWSET ya funcionar&amp;aacute; correctamente, llenando la tabla DatosPoblacion con el contenido del archivo GenerarDatosPoblacion.xlsx.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_15.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_15.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Optimizando la importaci&amp;oacute;n de datos de Excel&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En el punto actual podemos encontrarnos, no obstante, ante un problema de rendimiento, ya que si hemos seguido los pasos indicados anteriormente durante la creaci&amp;oacute;n del archivo Excel, tendremos una hoja de c&amp;aacute;lculo con un mill&amp;oacute;n de filas, que puede tardar alrededor de quince minutos en cargarse en la tabla de SQL Server. Para el ejemplo que estamos desarrollando en este art&amp;iacute;culo se ha utilizado una m&amp;aacute;quina virtual con Windows 7 como sistema operativo y 1,5 GB de memoria, por lo que los mencionados tiempos pueden variar en funci&amp;oacute;n de la configuraci&amp;oacute;n del equipo utilizado para estas pruebas.&lt;/p&gt;
&lt;p&gt;Si queremos disminuir estos tiempos de carga podemos optar por el uso de la t&amp;eacute;cnica alternativa de traspaso de datos que explicamos seguidamente.&lt;/p&gt;
&lt;p&gt;En primer lugar volveremos a abrir desde Excel el archivo GenerarDatosPoblacion.xlsx, guard&amp;aacute;ndolo como archivo de tipo &amp;quot;CSV (delimitado por comas)&amp;quot;.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_16.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_16.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;De esta forma obtendremos un archivo de texto con los campos delimitados por el car&amp;aacute;cter de punto y coma. Podemos ver su contenido abri&amp;eacute;ndolo con el Bloc de notas.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_17.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_17.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n crearemos en la base de datos una nueva tabla con la siguiente estructura.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; DatosPoblacionExcel (&lt;br /&gt;Fila_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Edad_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Sexo_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;CCAA_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Pais_ID &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Anualidad &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Mes &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Dia &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,&lt;br /&gt;Fecha_Alta &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(20) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;En esta nueva tabla importaremos el contenido del archivo GenerarDatosPoblacion.csv, utilizando la sentencia BULK INSERT de Transact-SQL. Mediante la opci&amp;oacute;n FIELDTERMINATOR especificaremos el car&amp;aacute;cter usado como separador de campos, mientras que con la opci&amp;oacute;n FIRSTROW indicaremos que la lectura de datos comience en la segunda fila del archivo, ya que la primera contiene los nombres de las columnas.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;BULK&lt;/span&gt; INSERT DatosPoblacionExcel&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;C:\DatosOrigen\GenerarDatosPoblacion.csv&amp;#39;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; (FIELDTERMINATOR =&lt;span style="color:#006080;"&gt;&amp;#39;;&amp;#39;&lt;/span&gt;, FIRSTROW=2)&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;El tiempo consumido por esta operaci&amp;oacute;n de inserci&amp;oacute;n masiva en la tabla DatosPoblacionExcel ser&amp;aacute; de unos treinta segundos.&lt;/p&gt;
&lt;p&gt;Para terminar con este proceso, insertaremos en la tabla DatosPoblacion los registros de la tabla DatosPoblacionExcel, excluyendo los campos innecesarios, como vemos en la siguiente sentencia, cuya ejecuci&amp;oacute;n tardar&amp;aacute; unos 15 segundos aproximadamente.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; DatosPoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; Fila_ID,Edad_ID,Sexo_ID,CCAA_ID,Pais_ID,Fecha_Alta&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; DatosPoblacionExcel&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Como acabamos de comprobar, esta t&amp;eacute;cnica de inserci&amp;oacute;n de datos, si bien nos obliga a realizar un paso adicional, supone una importante ganancia de tiempo, ya que emplea menos de un minuto en el traspaso de datos a la tabla DatosPoblacion, frente a los quince minutos utilizados por la funci&amp;oacute;n OPENROWSET.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Importando el resto de tablas cat&amp;aacute;logo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para las tablas CCAA y Pais, recurriremos a dos archivos Excel que contienen, respectivamente, la clasificaci&amp;oacute;n oficial de &lt;a href="http://www.madrid.org/iestadis/fijas/clasificaciones/descarga/ccaaprov.zip"&gt;comunidades aut&amp;oacute;nomas&lt;/a&gt; y &lt;a href="http://www.madrid.org/iestadis/fijas/clasificaciones/descarga/cozonu.zip"&gt;pa&amp;iacute;ses&lt;/a&gt;. Estos archivos se encuentran disponibles en formato comprimido, en el sitio Web del &lt;a href="http://www.madrid.org/iestadis/index.html"&gt;Instituto de Estad&amp;iacute;stica de la Comunidad de Madrid&lt;/a&gt;. Una vez descargados y descomprimidos ejecutaremos las siguientes sentencias SQL para importarlos a nuestra base de datos.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; CCAA&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DISTINCT&lt;/span&gt; ccaa, liteccaa&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;OPENROWSET&lt;/span&gt;(&lt;span style="color:#006080;"&gt;&amp;#39;Microsoft.Jet.OLEDB.4.0&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;Excel 8.0;Database=C:\DatosOrigen\ccaaprov.xls&amp;#39;&lt;/span&gt;, &lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;SELECT * FROM [ccaaprov$]&amp;#39;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Pais&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DISTINCT&lt;/span&gt; isopais,lpaisc&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;OPENROWSET&lt;/span&gt;(&lt;span style="color:#006080;"&gt;&amp;#39;Microsoft.Jet.OLEDB.4.0&amp;#39;&lt;/span&gt;,&lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;Excel 8.0;Database=C:\DatosOrigen\cozonu.xls&amp;#39;&lt;/span&gt;, &lt;br /&gt;&lt;span style="color:#006080;"&gt;&amp;#39;SELECT * FROM [cozonu$]&amp;#39;&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Observemos que seg&amp;uacute;n la versi&amp;oacute;n de Excel del archivo a importar, en la funci&amp;oacute;n OPENROWSET&amp;nbsp; utilizaremos un proveedor distinto para obtener los datos. Si el archivo corresponde a Excel 2007-2010 emplearemos &amp;#39;Microsoft.ACE.OLEDB.12.0&amp;#39;, mientras que para versiones anteriores ser&amp;aacute; &amp;#39;Microsoft.Jet.OLEDB.4.0&amp;#39;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Ajustando el c&amp;oacute;digo de pa&amp;iacute;s en la tabla DatosPoblacion&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si observamos con detenimiento los registros de la tabla Pais, nos percataremos de que los valores del campo Pais_ID no son correlativos; siendo, adem&amp;aacute;s, el valor menor 4 y el mayor 894.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_18.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_18.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esto contrasta con los datos existentes en el campo del mismo nombre correspondiente a la tabla DatosPoblacion, ya que, si bien el valor m&amp;aacute;ximo y m&amp;iacute;nimo de dicho campo tambi&amp;eacute;n est&amp;aacute; entre 4 y 894, encontraremos una buena cantidad de registros en los que el campo Pais_ID no corresponder&amp;aacute; a ning&amp;uacute;n valor en la tabla Pais.&lt;/p&gt;
&lt;p&gt;Para solucionar este problema vamos a recurrir a un par de t&amp;eacute;cnicas, de las cuales, la primera consistir&amp;aacute; en tomar, de la tabla DatosPoblacion, cada uno de los valores del campo Pais_ID que no existan en la tabla Pais, sum&amp;aacute;ndole uno hasta que lleguemos a un valor que s&amp;iacute; exista en la mencionada tabla cat&amp;aacute;logo de pa&amp;iacute;ses. Este proceso lo implementaremos en la funci&amp;oacute;n de SQL Server que vemos a continuaci&amp;oacute;n.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;FUNCTION&lt;/span&gt; dbo.ObtenerPais(@nPais_ID &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;RETURNS&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WHILE&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;COUNT&lt;/span&gt;(*) &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Pais &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; Pais_ID = @nPais_ID) = 0&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;BEGIN&lt;/span&gt;&lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; @nPais_ID = @nPais_ID + 1&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;    &lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;RETURN&lt;/span&gt; @nPais_ID&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;La actualizaci&amp;oacute;n del campo Pais_ID en la tabla DatosPoblacion la llevaremos a cabo con la siguiente sentencia.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;UPDATE&lt;/span&gt; DatosPoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; Pais_ID = dbo.ObtenerPais(Pais_ID)&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; Pais_ID &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;IN&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; Pais_ID &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Pais)&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;La segunda de las t&amp;eacute;cnicas resulta m&amp;aacute;s directa, ya que evitamos el uso de la funci&amp;oacute;n de b&amp;uacute;squeda del campo Pais_ID en la tabla de pa&amp;iacute;ses. Lo que hacemos en este caso es una actualizaci&amp;oacute;n del campo Pais_ID para toda la tabla DatosPoblacion, buscando en la tabla Pais, el valor de Pais_ID m&amp;aacute;s pr&amp;oacute;ximo al que existe en el mismo campo de la tabla DatosPoblacion.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;UPDATE&lt;/span&gt; DatosPoblacion&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;SET&lt;/span&gt; Pais_ID = (&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TOP&lt;/span&gt; 1 Pais.Pais_ID &lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Pais &lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;WHERE&lt;/span&gt; Pais.Pais_ID &amp;gt;= DatosPoblacion.Pais_ID &lt;br /&gt;    &lt;span style="color:#0000ff;"&gt;ORDER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;BY&lt;/span&gt; Pais.Pais_ID)&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;En ambos casos, conseguimos que todos los registros de la tabla DatosPoblacion crucen correctamente con la tabla Pais por el campo Pais_ID.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Inserci&amp;oacute;n manual de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Despu&amp;eacute;s de las operaciones anteriores, la &amp;uacute;nica tabla que permanece sin datos es Sexo, por lo que ejecutaremos las siguientes sentencias, que crear&amp;aacute;n los registros necesarios.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Sexo &lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;H&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Hombre&amp;#39;&lt;/span&gt;)&lt;br /&gt;INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Sexo &lt;span style="color:#0000ff;"&gt;VALUES&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;M&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Mujer&amp;#39;&lt;/span&gt;)&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Estableciendo relaciones entre las tablas&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para finalizar la creaci&amp;oacute;n de la base de datos, estableceremos las oportunas relaciones entre los campos de la tabla DatosPoblacion y el resto de tablas cat&amp;aacute;logo, utilizando las siguientes sentencias.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;ALTER&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; DatosPoblacion &lt;span style="color:#0000ff;"&gt;WITH&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CHECK&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;ADD&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; FK_DatosPoblacion_Sexo &lt;span style="color:#0000ff;"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt;(Sexo_ID) &lt;span style="color:#0000ff;"&gt;REFERENCES&lt;/span&gt; Sexo (Sexo_ID),&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; FK_DatosPoblacion_CCAA &lt;span style="color:#0000ff;"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt;(CCAA_ID) &lt;span style="color:#0000ff;"&gt;REFERENCES&lt;/span&gt; CCAA (CCAA_ID),&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; FK_DatosPoblacion_Pais &lt;span style="color:#0000ff;"&gt;FOREIGN&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt;(Pais_ID) &lt;span style="color:#0000ff;"&gt;REFERENCES&lt;/span&gt; Pais (Pais_ID)&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Despu&amp;eacute;s de esta operaci&amp;oacute;n damos por concluido este art&amp;iacute;culo, en el que hemos explicado las diferentes partes de un proceso para generar, desde Excel, un volumen considerable de datos de prueba, que poder utilizar posteriormente desde SQL Server. En el siguiente &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201104/GenerarDatosPruebaExcelEjemplosZip.txt"&gt;enlace&lt;/a&gt; se encuentra disponible el c&amp;oacute;digo del ejemplo.&amp;nbsp;Esperamos que os resulte de utilidad.&lt;/p&gt;
&lt;p&gt;Un saludo.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=193179" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Trucos" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Trucos/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /></entry><entry><title>Programación en Silverlight 4.0, de Marino Posadas</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/04/27/programaci-243-n-en-silverlight-4-0-de-marino-posadas.aspx" /><id>/blogs/lmblanco/archive/2011/04/27/programaci-243-n-en-silverlight-4-0-de-marino-posadas.aspx</id><published>2011-04-27T18:59:00Z</published><updated>2011-04-27T18:59:00Z</updated><content type="html">&lt;p&gt;Marino Posadas acaba de publicar un libro sobre Silverlight 4.0, en el que como es su costumbre, adem&amp;aacute;s de realizar una introducci&amp;oacute;n a esta tecnolog&amp;iacute;a, aborda con profundidad y profusi&amp;oacute;n todos aquellos aspectos necesarios para capacitarnos en la construcci&amp;oacute;n de aplicaciones para esta versi&amp;oacute;n de Silverlight.&lt;/p&gt;
&lt;p&gt;Tras la parte inicial dedicada a la arquitectura de Silverlight y las aplicaciones RIA, as&amp;iacute; como el obligado cap&amp;iacute;tulo sobre XAML, el texto nos ofrece una serie de detallados cap&amp;iacute;tulos sobre las caracter&amp;iacute;sticas visuales, layout, aplicaci&amp;oacute;n de transformaciones, 3D, interacci&amp;oacute;n con el modelo HTML-DOM y un abordaje de Expression Blend 4 desde la perspectiva del desarrollador. Finalmente, como colof&amp;oacute;n, encontramos un cap&amp;iacute;tulo dedicado a Windows Phone 7, esencial para todo aquel que quiera iniciarse en el desarrollo de aplicaciones para los dispositivos m&amp;oacute;viles que funcionan bajo esta plataforma.&lt;/p&gt;
&lt;p&gt;En resumen, un excelente libro de un no menos excelente autor, que ya est&amp;aacute; disponible en &lt;a href="http://www.dotnetmania.com/libros/"&gt;dotNetMan&amp;iacute;a&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Un saludo.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=193094" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="Silverlight" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Silverlight/default.aspx" /><category term="WCF RIA Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/WCF+RIA+Services/default.aspx" /></entry><entry><title>Generar datos de prueba para SQL Server desde Excel. Operaciones en Excel (1)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/04/26/generar-datos-de-prueba-para-sql-server-desde-excel-operaciones-desde-excel-1.aspx" /><id>/blogs/lmblanco/archive/2011/04/26/generar-datos-de-prueba-para-sql-server-desde-excel-operaciones-desde-excel-1.aspx</id><published>2011-04-26T17:20:00Z</published><updated>2011-04-26T17:20:00Z</updated><content type="html">&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;La creaci&amp;oacute;n de datos de muestreo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Durante las diversas fases del desarrollo de una aplicaci&amp;oacute;n, en la mayor parte de las ocasiones, nos encontramos ante la necesidad de tener a nuestra disposici&amp;oacute;n un conjunto de datos de prueba, para poder utilizarlos en los diferentes procesos que estamos desarrollando. Una situaci&amp;oacute;n similar se produce si estamos construyendo un sistema de informaci&amp;oacute;n basado en cubos de datos OLAP mediante SQL Server Analysis Services, ya que, por lo general, en estos casos necesitaremos adem&amp;aacute;s, que el volumen de los datos sea de un tama&amp;ntilde;o considerable, para poder realizar simulaciones de an&amp;aacute;lisis.&lt;/p&gt;
&lt;p&gt;Supongamos que tenemos que generar una base de datos con informaci&amp;oacute;n poblacional, en la que una tabla albergar&amp;iacute;a los datos de los individuos tales como edad, c&amp;oacute;digos de comunidad aut&amp;oacute;noma de residencia, pa&amp;iacute;s de procedencia, sexo, fecha de alta en el registro, etc. Por otro lado, necesitar&amp;iacute;amos tambi&amp;eacute;n una serie de tablas cat&amp;aacute;logo de pa&amp;iacute;ses, comunidades aut&amp;oacute;nomas, y dem&amp;aacute;s valores relacionados con los campos de la tabla de individuos.&lt;/p&gt;
&lt;p&gt;Entre todo el abanico de utilidades, trucos, etc., que existen para llevar a cabo esta tarea, en el presente art&amp;iacute;culo haremos uso de Excel como herramienta para la generaci&amp;oacute;n del conjunto de datos ficticios correspondiente a los individuos, que posteriormente volcaremos en una base de datos SQL Server, la cual podr&amp;iacute;amos usar como fuente de datos de la aplicaci&amp;oacute;n o sistema en desarrollo.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creando los datos con Excel&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Una vez iniciado Excel 2010 (tambi&amp;eacute;n podemos utilizar versiones anteriores), nuestra primera tarea ser&amp;aacute; la creaci&amp;oacute;n de una columna con los valores que nos servir&amp;aacute;n para identificar las filas de la tabla. La forma m&amp;aacute;s simple de generarlos, consiste en introducir un par de n&amp;uacute;meros correlativos en sendas celdas de una de las columnas de la hoja de c&amp;aacute;lculo, seleccionar ambas celdas, y arrastrar el marcador de relleno hasta la &amp;uacute;ltima fila para la cual queramos generar los n&amp;uacute;meros.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_01.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_01.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;No obstante, la generaci&amp;oacute;n de valores mediante esta t&amp;eacute;cnica puede resultar un tanto engorrosa en el caso de que debamos producir una gran cantidad de filas y/o columnas, por lo que para la creaci&amp;oacute;n de datos en todas las columnas de la hoja vamos a recurrir a un medio m&amp;aacute;s flexible a la par que potente: las macros de Excel.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creaci&amp;oacute;n de una macro&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Para crear una macro haremos clic en la pesta&amp;ntilde;a Vista de la cinta de opciones de Excel, y dentro del grupo Macros haremos clic en la opci&amp;oacute;n del mismo nombre, que abrir&amp;aacute; el cuadro de di&amp;aacute;logo Macro, donde escribiremos el nombre de nuestra macro: CrearDatosPoblacion.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_02.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_02.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Haciendo clic en el bot&amp;oacute;n Crear, se abrir&amp;aacute; la ventana de Visual Basic para Aplicaciones (VBA), con el editor de la nueva macro reci&amp;eacute;n creada, para que podamos empezar a escribir su c&amp;oacute;digo.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_03.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_03.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Dentro del cuerpo del procedimiento CrearDatosPoblaci&amp;oacute;n, escribiremos el siguiente bloque de c&amp;oacute;digo, donde en primer lugar, limpiaremos las celdas de la hoja de c&amp;aacute;lculo en la que estemos actualmente posicionados. A continuaci&amp;oacute;n solicitaremos al usuario que introduzca, mediante una caja de di&amp;aacute;logo InputBox, el n&amp;uacute;mero de filas a generar. Despu&amp;eacute;s de insertar el t&amp;iacute;tulo de la columna, introduciremos los dos primeros valores que inician la serie, la cual generaremos mediante el m&amp;eacute;todo Selection.AutoFill.&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;Option&lt;/span&gt; Explicit&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Sub&lt;/span&gt; CrearDatosPoblacion()&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; nFilaDestino &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Long&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sCeldaOrigen &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;Dim&lt;/span&gt; sCeldaDestino &lt;span style="color:#0000ff;"&gt;As&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;limpiar las celdas de la hoja de c&amp;aacute;lculo&lt;/span&gt;&lt;br /&gt;Cells.&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;Selection.ClearContents&lt;br /&gt;&lt;br /&gt;nFilaDestino = InputBox(&lt;span style="color:#006080;"&gt;&amp;quot;N&amp;uacute;mero de registros a generar&amp;quot;&lt;/span&gt;)&lt;br /&gt;nFilaDestino = nFilaDestino + 1&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;columna fila_id&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;---------------&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;t&amp;iacute;tulo de columna&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Fila_ID&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;valores iniciales de la serie a generar&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A2&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;1&amp;quot;&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A3&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;seleccionar rango de valores iniciales&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;A2:A3&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;rellenar rango total de celdas&lt;/span&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;A2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;A&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Selection.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;End&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;Sub&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_04.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_04.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para ejecutar la macro seleccionaremos la opci&amp;oacute;n de men&amp;uacute; Ejecutar | Ejecutar Sub/UserForm, o pulsaremos la tecla F5, rellen&amp;aacute;ndose la primera columna de la hoja con la cantidad de valores indicada en el InputBox.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_05.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_05.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Antes de proseguir grabaremos nuestro trabajo desde la ventana de VBA o de Excel, teniendo en cuenta que deberemos hacerlo en un archivo de tipo &amp;quot;Libro de Excel habilitado para macros&amp;quot; (extensi&amp;oacute;n .xlsm), de lo que seremos avisados por un cuadro de di&amp;aacute;logo en el momento de la grabaci&amp;oacute;n. Haciendo clic en el bot&amp;oacute;n No de dicho di&amp;aacute;logo, guardaremos nuestra hoja de c&amp;aacute;lculo en un archivo con el nombre GenerarDatosPoblacion.xlsm.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_06.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_06.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Generaci&amp;oacute;n de datos aleatorios&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;La siguiente columna a crear corresponder&amp;aacute; a la edad de las personas; en ella, necesitaremos generar valores aleatorios entre un intervalo de n&amp;uacute;meros, que representen las edades m&amp;aacute;xima y m&amp;iacute;nima que una persona puede tener, por ejemplo, entre 0 y 120.&lt;/p&gt;
&lt;p&gt;Para crear, en una celda de Excel, un valor aleatorio comprendido entre dos n&amp;uacute;meros, podemos utilizar una f&amp;oacute;rmula que incluya la funci&amp;oacute;n ALEATORIO.ENTRE, que recibe como par&amp;aacute;metro los mencionados n&amp;uacute;meros, devolviendo como resultado el n&amp;uacute;mero generado.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_07.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_07.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Trasladando esta funcionalidad a la macro que estamos desarrollando, a&amp;ntilde;adiremos a la misma el siguiente bloque de c&amp;oacute;digo, en el que asignaremos a una celda de la segunda columna una expresi&amp;oacute;n de f&amp;oacute;rmula conteniendo RANDBETWEEN(0,120) (equivalente a la funci&amp;oacute;n ALEATORIO.ENTRE), seleccionaremos dicha celda, y repetiremos la f&amp;oacute;rmula que contiene a lo largo del rango de celdas, usando el m&amp;eacute;todo ActiveCell.AutoFill.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;edad&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;----&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;B1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Edad_ID&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;B2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;B&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=RANDBETWEEN(0,120)&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Ejecutando otra vez la macro, obtendremos la nueva columna con los datos de edad.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_08.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_08.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En nuestro siguiente paso le toca el turno a la columna con los valores para el sexo de los individuos. Aqu&amp;iacute; podr&amp;iacute;amos haber usado dos n&amp;uacute;meros: 1 y 2, generados igualmente de forma aleatoria, para identificar respectivamente a hombre y mujer, pero vamos a complicar un poco esta operaci&amp;oacute;n, utilizando en su lugar las letras H y M como valores para la columna, por lo que el problema se encuentra ahora en c&amp;oacute;mo generar aleatoriamente estas letras en las celdas de la columna, ya que la funci&amp;oacute;n RANDBETWEEN s&amp;oacute;lo recibe y devuelve resultados num&amp;eacute;ricos.&lt;/p&gt;
&lt;p&gt;La soluci&amp;oacute;n es muy simple, ya que tambi&amp;eacute;n consiste en utilizar la funci&amp;oacute;n RANDBETWEEN, pero combin&amp;aacute;ndola con la expresi&amp;oacute;n de decisi&amp;oacute;n IF. A RANDBETWEEN le pasaremos los n&amp;uacute;meros 1 y 2 como par&amp;aacute;metros, y seg&amp;uacute;n el resultado obtenido, mediante IF devolveremos la letra H o M. A continuaci&amp;oacute;n se muestra el bloque de c&amp;oacute;digo para esta columna, que a&amp;ntilde;adiremos a la macro.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;sexo&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;----&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;C1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Sexo_ID&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;C2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;C&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=IF(RANDBETWEEN(1,2)=1,&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot;H&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot;M&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot;)&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_09.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_09.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para las dos siguientes columnas: c&amp;oacute;digo de comunidad aut&amp;oacute;noma de residencia y c&amp;oacute;digo de pa&amp;iacute;s de procedencia, seguiremos la misma mec&amp;aacute;nica que en la columna de edades, si bien utilizando distintos intervalos num&amp;eacute;ricos.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;ccaa&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;----&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;D1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;CCAA_ID&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;D2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;D&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=RANDBETWEEN(1,19)&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;pa&amp;iacute;s&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;----&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;E1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Pais_ID&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;E2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;E&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=RANDBETWEEN(4,894)&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_10.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_10.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Nuestro siguiente paso consistir&amp;aacute; en crear los datos de una supuesta fecha de alta de los individuos en este sistema poblacional, tarea que realizaremos en dos fases. En primer lugar, crearemos cada parte de la fecha en columnas separadas.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;elementos de fecha:&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;===================&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;a&amp;ntilde;o&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;---&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;F1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Anualidad&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;F2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;F&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=RANDBETWEEN(2008,2010)&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;mes&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;---&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;G1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Mes&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;G2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;G&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=RANDBETWEEN(1,12)&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;d&amp;iacute;a&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;---&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;H1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Dia&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;H2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;H&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=IF(RC[-1]=2, RANDBETWEEN(1,28), IF(OR(RC[-1]=4, RC[-1]=6, RC[-1]=9, RC[-1]=11), RANDBETWEEN(1,30), RANDBETWEEN(1,31)))&amp;quot;&lt;/span&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Como acabamos de ver, el d&amp;iacute;a es la parte de la fecha que requiere mayor trabajo, ya que debemos poner cuidado en evitar la generaci&amp;oacute;n, por ejemplo, de un d&amp;iacute;a 31 si en la columna de mes tenemos el valor 2. Esto lo solucionaremos comprobando, en primer lugar, el valor de dicha columna de mes, y en funci&amp;oacute;n del mismo, usaremos un intervalo distinto para generar el d&amp;iacute;a; para ello, en la f&amp;oacute;rmula utilizaremos varias expresiones IF combinadas con funciones RANDBETWEEN.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_11.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_11.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;En la segunda fase de esta operaci&amp;oacute;n, crearemos una &amp;uacute;ltima columna en la hoja de c&amp;aacute;lculo con una fecha en un formato comprensible para SQL Server, fruto de la concatenaci&amp;oacute;n de las anteriores columnas de anualidad, mes y d&amp;iacute;a.&lt;/p&gt;
&lt;p&gt;Es necesario tener en cuenta, al componer la fecha de esta manera, que debemos a&amp;ntilde;adir un cero al mes y al d&amp;iacute;a, cuando estos valores tengan solamente un d&amp;iacute;gito.&amp;nbsp;&lt;/p&gt;
&lt;div id="codeSnippetWrapper"&gt;
&lt;pre id="codeSnippet" style="text-align:left;line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:&amp;#39;Courier New&amp;#39;, Courier, Monospace;direction:ltr;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;&amp;#39;componer fecha&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#008000;"&gt;&amp;#39;--------------&lt;/span&gt;&lt;br /&gt;Range(&lt;span style="color:#006080;"&gt;&amp;quot;I1&amp;quot;&lt;/span&gt;).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;Fecha_Alta&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;sCeldaOrigen = &lt;span style="color:#006080;"&gt;&amp;quot;I2&amp;quot;&lt;/span&gt;&lt;br /&gt;sCeldaDestino = &lt;span style="color:#006080;"&gt;&amp;quot;I&amp;quot;&lt;/span&gt; &amp;amp; nFilaDestino&lt;br /&gt;Range(sCeldaOrigen).&lt;span style="color:#0000ff;"&gt;Select&lt;/span&gt;&lt;br /&gt;ActiveCell.FormulaR1C1 = &lt;span style="color:#006080;"&gt;&amp;quot;=RC[-3] &amp;amp; IF(LEN(RC[-2])=1,&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot; &amp;amp; RC[-2],RC[-2]) &amp;amp; &amp;quot;&lt;/span&gt; &amp;amp; _&lt;br /&gt;    &lt;span style="color:#006080;"&gt;&amp;quot;IF(LEN(RC[-1])=1,&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span style="color:#006080;"&gt;&amp;quot; &amp;amp; RC[-1],RC[-1]) &amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ActiveCell.AutoFill Destination:=Range(sCeldaOrigen &amp;amp; &lt;span style="color:#006080;"&gt;&amp;quot;:&amp;quot;&lt;/span&gt; &amp;amp; sCeldaDestino), Type:=xlFillDefault&lt;br /&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;p&gt;Al volver a ejecutar la macro, obtendremos la fecha correctamente formateada en la &amp;uacute;ltima columna. En esta ocasi&amp;oacute;n, adem&amp;aacute;s, estableceremos la cifra de registros a generar en un mill&amp;oacute;n, de esa forma probaremos el potencial de creaci&amp;oacute;n de los datos.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_12.jpg"&gt;&lt;img src="http://geeks.ms/resized-image.ashx/__size/550x0/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201104/GenerarDatosPruebaParaSQLServerDesdeExcel_5F00_12.jpg" border="0" alt="" /&gt;&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Para finalizar las operaciones con Excel grabaremos el archivo, esta vez con formato de &amp;quot;Libro de Excel&amp;quot; (extensi&amp;oacute;n .xlsx). Nuevamente aparecer&amp;aacute; el cuadro de di&amp;aacute;logo de aviso, que nos informar&amp;aacute; de que no podemos guardar las macros en un archivo .xlsx, al que contestaremos haciendo clic en S&amp;iacute;.&lt;/p&gt;
&lt;p&gt;Llegados a este punto concluimos la primera parte del art&amp;iacute;culo; en la segunda entrega explicaremos c&amp;oacute;mo traspasar los datos que acabamos de crear a SQL Server.&lt;/p&gt;
&lt;p&gt;Un saludo.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=193001" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="SQL Server" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server/default.aspx" /><category term="Trucos" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Trucos/default.aspx" /><category term="SQL Server 2008 R2" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/SQL+Server+2008+R2/default.aspx" /><category term="Excel" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Excel/default.aspx" /></entry><entry><title>Acceso a datos en Silverlight mediante DomainDataSource</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/03/29/acceso-a-datos-en-silverlight-mediante-domaindatasource.aspx" /><id>/blogs/lmblanco/archive/2011/03/29/acceso-a-datos-en-silverlight-mediante-domaindatasource.aspx</id><published>2011-03-29T18:00:00Z</published><updated>2011-03-29T18:00:00Z</updated><content type="html">&lt;p&gt;En el pasado n&amp;uacute;mero 78 de &lt;a href="http://www.dotnetmania.com/"&gt;dotNetMan&amp;iacute;a&lt;/a&gt; publiqu&amp;eacute; un art&amp;iacute;culo titulado &amp;quot;DomainDataSource. Un gestor de datos en Silverlight para la interfaz de usuario&amp;quot;, sobre el uso del componente DomainDataSource en la realizaci&amp;oacute;n de las operaciones de manejo de datos en una aplicaci&amp;oacute;n Silverlight. Se trata de un art&amp;iacute;culo que tambi&amp;eacute;n se encuentra disponible en los siguientes sitios web: &lt;a href="http://www.programacion.com/articulo/domaindatasource-_un_gestor_de_datos_en_silverlight_para_la_interfaz_de_usuario_712"&gt;enlace1&lt;/a&gt; y &lt;a href="http://www.desarrolloweb.com/articulos/domaindatasource-dotnet.html"&gt;enlace2&lt;/a&gt;. Espero que os resulte de utilidad.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Un saludo.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=191265" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="Silverlight" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Silverlight/default.aspx" /><category term="WCF RIA Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/WCF+RIA+Services/default.aspx" /></entry><entry><title>La licencia de .NET Reflector pasa a ser de pago</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/02/02/la-licencia-de-net-reflector-pasa-a-ser-de-pago.aspx" /><id>/blogs/lmblanco/archive/2011/02/02/la-licencia-de-net-reflector-pasa-a-ser-de-pago.aspx</id><published>2011-02-02T18:17:00Z</published><updated>2011-02-02T18:17:00Z</updated><content type="html">&lt;p&gt;Despu&amp;eacute;s de la&amp;nbsp;adquisici&amp;oacute;n de &lt;a href="http://www.red-gate.com/products/dotnet-development/reflector/"&gt;.NET Reflector&lt;/a&gt;&amp;nbsp;por parte de &lt;a href="http://www.red-gate.com/"&gt;Red Gate&lt;/a&gt; hace alrededor de dos a&amp;ntilde;os y medio, finalmente ha ocurrido algo que m&amp;aacute;s o menos creo que todos pens&amp;aacute;bamos que suceder&amp;iacute;a. Red Gate empezar&amp;aacute; a cobrar a principios de marzo por la licencia de .NET Reflector. En el siguiente &lt;a href="http://www.youtube.com/watch?v=TKnEjiSGZLA&amp;amp;feature=player_embedded"&gt;video&lt;/a&gt;, Simon Galbraith, uno de los responsables de la compa&amp;ntilde;&amp;iacute;a, explica las motivaciones que les han llevado a tomar esta medida.&lt;/p&gt;
&lt;p&gt;Un saludo.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=188337" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term=".NET" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/.NET/default.aspx" /><category term="Varios" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Varios/default.aspx" /></entry><entry><title>Mejorando la experiencia de usuario en el control DataForm de Silverlight (y 3)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/01/26/mejorando-la-experiencia-de-usuario-en-el-control-dataform-de-silverlight-y-3.aspx" /><id>/blogs/lmblanco/archive/2011/01/26/mejorando-la-experiencia-de-usuario-en-el-control-dataform-de-silverlight-y-3.aspx</id><published>2011-01-26T17:57:00Z</published><updated>2011-01-26T17:57:00Z</updated><content type="html">&lt;p&gt;En esta tercera entrega del art&amp;iacute;culo seguiremos con nuestra tarea de editar los campos del DataForm usando dos controles sobradamente conocidos por la gran mayor&amp;iacute;a de desarrolladores: ComboBox y RadioButton. El c&amp;oacute;digo fuente del proyecto est&amp;aacute; disponible &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201012/DataFormUXZip.txt"&gt;aqu&amp;iacute;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;ComboBox. Seleccionando el valor del campo en una lista desplegable&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Continuamos con las operaciones de selecci&amp;oacute;n en listas de valores de la mano de uno de los grandes cl&amp;aacute;sicos entre los controles de usuario: ComboBox.&lt;/p&gt;
&lt;p&gt;Del mismo modo que en los anteriores controles, el control ComboBox tambi&amp;eacute;n necesita una colecci&amp;oacute;n de elementos para mostrar en su lista desplegable; pero en este caso, en lugar de tratarse de una colecci&amp;oacute;n simple de valores, emplearemos la colecci&amp;oacute;n de entidades de tipo Customer obtenidas a partir del control DomainDataSource ddsCustomers, que anteriormente a&amp;ntilde;adimos a la p&amp;aacute;gina MainPage.xaml.&lt;/p&gt;
&lt;p&gt;En primer lugar trasladaremos el control ddsCustomers al bloque de recursos de la p&amp;aacute;gina XAML, operaci&amp;oacute;n necesaria para que el ComboBox tenga acceso a los datos que ddsCustomers proporciona. Adicionalmente, ordenaremos por la propiedad CustomerName de los objetos Customer el resultado devuelto por este DomainDataSource, utilizando para ello una etiqueta SortDescriptors.&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n a&amp;ntilde;adiremos un ComboBox a la plantilla EditTemplate del DataForm, dentro del DataField reservado a la informaci&amp;oacute;n del cliente de la factura. El c&amp;oacute;digo XAML que emplearemos ser&amp;aacute; el siguiente.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl.Resources&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;ddsCustomers&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;QueryName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;GetCustomers&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.DomainContext&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;domainctx:MusicaGestDomainContext&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.DomainContext&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.SortDescriptors&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:SortDescriptor&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;PropertyPath&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;CustomerName&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.SortDescriptors&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl.Resources&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.EditTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Cliente:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Orientation&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Horizontal&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=CustomerId, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                     &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;40&amp;quot;&lt;/span&gt; 
                     &lt;span style="color:#ff0000;"&gt;IsEnabled&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;

            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComboBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;cboCustomers&amp;quot;&lt;/span&gt; 
                      &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;200&amp;quot;&lt;/span&gt; 
                      &lt;span style="color:#ff0000;"&gt;Margin&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;5,0,0,0&amp;quot;&lt;/span&gt;
                      &lt;span style="color:#ff0000;"&gt;ItemsSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Source={StaticResource ddsCustomers}, Path=Data}&amp;quot;&lt;/span&gt;
                      &lt;span style="color:#ff0000;"&gt;DisplayMemberPath&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;CustomerName&amp;quot;&lt;/span&gt;
                      &lt;span style="color:#ff0000;"&gt;SelectedValuePath&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;CustomerId&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Respecto a la configuraci&amp;oacute;n de las propiedades del ComboBox, a la propiedad ItemsSource le asignaremos una expresi&amp;oacute;n de enlace a datos cuya fuente sea el DomainDataSource que hemos situado como recurso; mientras que las propiedades DisplayMemberPath y SelectedValuePath contendr&amp;aacute;n, respectivamente, los valores CustomerName y CustomerId, que corresponden a los nombres de las propiedades de los objetos Customer contenidos en la colecci&amp;oacute;n de entidades asignada al ComboBox. Con DisplayMemberPath le indicamos al ComboBox la propiedad a utilizar para los valores a mostrar en la lista, y SelectedValuePath es la propiedad que el control utilizar&amp;aacute; internamente para informar al DataForm del identificador de cliente seleccionado para la factura.&lt;/p&gt;
&lt;p&gt;En el estado actual de la aplicaci&amp;oacute;n, cada vez que hagamos clic en el bot&amp;oacute;n de edici&amp;oacute;n del DataForm, el ComboBox siempre mostrar&amp;aacute;, para CustomerName, el primer valor de la colecci&amp;oacute;n, sin mantener la adecuada correspondencia con el valor de CustomerId.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_12.JPG" border="0" style="max-height:390px;max-width:407px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Para corregir este comportamiento err&amp;oacute;neo, en primer lugar, a trav&amp;eacute;s de la propiedad x:Name, asignaremos un nombre al control TextBox que contiene el valor del campo CustomerId.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;txtCustomerId&amp;quot;&lt;/span&gt;
         &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=CustomerId, Mode=TwoWay}&amp;quot;&lt;/span&gt;
         &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;40&amp;quot;&lt;/span&gt;
         &lt;span style="color:#ff0000;"&gt;IsEnabled&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Seguidamente escribiremos en el manipulador del evento ContentLoaded del DataForm un bloque de c&amp;oacute;digo en el que obtendremos la instancia del mencionado TextBox y el contexto de dominio del control ddsCustomers. Ambos objetos nos permitir&amp;aacute;n construir una expresi&amp;oacute;n LINQ, que tendr&amp;aacute; como resultado el objeto Customer cuya propiedad CustomerId corresponde &amp;nbsp;al cliente actual de la factura. Como &amp;uacute;ltimo paso de este proceso recuperaremos la instancia del ComboBox y asignaremos a su propiedad SelectedItem el objeto Customer obtenido.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; frmInvoices_ContentLoaded(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, DataFormContentLoadEventArgs e)
{
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (e.Mode == DataFormMode.Edit)
    {
        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
        TextBox txtCustomerId = (TextBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;txtCustomerId&amp;quot;&lt;/span&gt;);

        MusicaGestDomainContext oDomCtxCustomers = (MusicaGestDomainContext)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ddsCustomers.DomainContext;

        Customer oCustomerActual = (from oCustomer &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDomCtxCustomers.Customers
                         &lt;span style="color:#0000ff;"&gt;where&lt;/span&gt; oCustomer.CustomerId == &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;.Parse(txtCustomerId.Text)
                         select oCustomer).Single();

        ComboBox cboCustomers = (ComboBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;cboCustomers&amp;quot;&lt;/span&gt;);

        cboCustomers.SelectedItem = oCustomerActual;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;A partir de ahora, el elemento visualizado por el ComboBox s&amp;iacute; corresponder&amp;aacute; con el valor adecuado cada vez que entremos en el modo de edici&amp;oacute;n del formulario de datos.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_13.JPG" border="0" style="max-height:391px;max-width:408px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;No obstante, el comportamiento del ComboBox dentro del formulario de datos sigue sin ser adecuado. Expliquemos esto con m&amp;aacute;s detalle: cuando situados en modo de edici&amp;oacute;n, el usuario modifica un campo del DataForm, &amp;eacute;ste detecta el cambio habilitando el bot&amp;oacute;n OK para poder hacer clic en &amp;eacute;l y confirmar las modificaciones. Esta situaci&amp;oacute;n no se est&amp;aacute; produciendo actualmente para el ComboBox, ya que la selecci&amp;oacute;n de un nuevo valor en dicho control no hace que se active el bot&amp;oacute;n OK.&lt;/p&gt;
&lt;p&gt;Para conseguir esta funcionalidad vamos a escribir un bloque de c&amp;oacute;digo en el manipulador del evento SelectionChanged del ComboBox. Dentro de dicho evento recuperaremos las instancias de los controles ComboBox y TextBox, asignando a este &amp;uacute;ltimo el valor seleccionado en la lista desplegable, lo que producir&amp;aacute; la activaci&amp;oacute;n del bot&amp;oacute;n OK del DataForm.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;ComboBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;cboCustomers&amp;quot;&lt;/span&gt; 
....
          &lt;span style="color:#ff0000;"&gt;SelectionChanged&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;cboCustomers_SelectionChanged&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;/div&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;p&gt;&lt;span style="color:#0000ff;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; cboCustomers_SelectionChanged(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, SelectionChangedEventArgs e)
{            
    ComboBox cboCustomers = (ComboBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;cboCustomers&amp;quot;&lt;/span&gt;);

    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (cboCustomers != &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
    {
        &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sCustomerIdComboBox = cboCustomers.SelectedValue.ToString();
        TextBox txtCustomerId = (TextBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;txtCustomerId&amp;quot;&lt;/span&gt;);
        txtCustomerId.Text = sCustomerIdComboBox;
    }
}
&lt;/p&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_14.JPG" border="0" style="max-height:396px;max-width:406px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Empleando esta t&amp;eacute;cnica ya hemos conseguido que el control ComboBox trabaje de manera coordinada con la maquinaria del DataForm. Sin embargo, demos otra vuelta de tuerca a esta situaci&amp;oacute;n: supongamos que en la plantilla EditTemplate del formulario prescindimos del TextBox txtCustomerId, &amp;iquest;c&amp;oacute;mo conseguimos entonces que el DataForm se percate de los cambios de selecci&amp;oacute;n que hagamos en el ComboBox?&lt;/p&gt;
&lt;p&gt;La soluci&amp;oacute;n pasa por manipular la propiedad DataForm.CurrentItem, la cual contiene el objeto que representa a la entidad actualmente en edici&amp;oacute;n en el formulario de datos; en nuestro caso un objeto Invoice.&lt;/p&gt;
&lt;p&gt;Primeramente escribiremos el siguiente bloque de c&amp;oacute;digo en el evento DataForm.ContentLoaded, que nos permitir&amp;aacute; establecer el valor correcto en el ComboBox al entrar en el modo de edici&amp;oacute;n del formulario.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; frmInvoices_ContentLoaded(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, DataFormContentLoadEventArgs e)
{
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (e.Mode == DataFormMode.Edit)
    {
        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
        Invoice oInvoiceActual = (Invoice)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.CurrentItem;

        MusicaGestDomainContext oDomCtxCustomers = (MusicaGestDomainContext)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ddsCustomers.DomainContext;

        Customer oCustomerActual = (from oCustomer &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDomCtxCustomers.Customers
                                    &lt;span style="color:#0000ff;"&gt;where&lt;/span&gt; oCustomer.CustomerId == oInvoiceActual.CustomerId
                                    select oCustomer).Single();

        ComboBox cboCustomers = (ComboBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;cboCustomers&amp;quot;&lt;/span&gt;);

        cboCustomers.SelectedItem = oCustomerActual;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;A continuaci&amp;oacute;n procederemos de forma similar en el evento ComboBox.SelectionChanged; esta vez &amp;nbsp;para asignar el valor seleccionado en el ComboBox a la propiedad Invoice.CustomerId de la entidad actualmente en edici&amp;oacute;n.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; cboCustomers_SelectionChanged(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, SelectionChangedEventArgs e)
{
    ComboBox cboCustomers = (ComboBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;cboCustomers&amp;quot;&lt;/span&gt;);

    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (cboCustomers != &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;)
    {
        &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; nCustomerIdComboBox = (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)cboCustomers.SelectedValue;
        Invoice oInvoiceActual = (Invoice)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.CurrentItem;
        oInvoiceActual.CustomerId = nCustomerIdComboBox;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Como resultado, al editar ahora la entidad en el DataForm, en el campo del cliente s&amp;oacute;lo aparecer&amp;aacute; el ComboBox.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_15.JPG" border="0" style="max-height:392px;max-width:408px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;RadioButton. Selecci&amp;oacute;n de opciones autoexcluyentes&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;RadioButton es un control que representa una alternativa m&amp;aacute;s en la manera en que podemos editar/seleccionar los valores para un campo en el DataForm, ya que mediante un conjunto de controles de este tipo, podemos ofrecer al usuario varias opciones entre las cuales elegir una para asignar como valor al campo del formulario.&lt;/p&gt;
&lt;p&gt;Vamos a emplear este control para editar el campo Region de la tabla Invoice. Dicho campo tiene cinco valores posibles en esta tabla: Asia, Europe, North America, South America y Oceania, por lo que a&amp;ntilde;adiremos el mismo n&amp;uacute;mero de controles RadioButton a nuestra p&amp;aacute;gina, dentro de la plantilla EditTemplate del DataForm, usando el siguiente bloque de c&amp;oacute;digo XAML.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Regi&amp;oacute;n:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;RadioButton&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtAsia&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Content&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Asia&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GroupName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Region&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Checked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtRegion_Checked&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;RadioButton&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtEurope&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Content&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Europe&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GroupName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Region&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Checked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtRegion_Checked&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;RadioButton&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtNorthAmerica&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Content&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;North America&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GroupName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Region&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Checked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtRegion_Checked&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;RadioButton&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtSouthAmerica&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Content&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;South America&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GroupName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Region&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Checked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtRegion_Checked&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;RadioButton&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtOceania&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Content&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Oceania&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;GroupName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Region&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Checked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;rbtRegion_Checked&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Para que el formulario considere a todos estos controles como pertenecientes a un mismo grupo, de forma que solamente uno de ellos pueda estar seleccionado a la vez, hemos asignado el mismo valor a su propiedad GroupName.&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n necesitamos codificar la l&amp;oacute;gica para que el RadioButton adecuado quede marcado cuando entramos en modo de edici&amp;oacute;n de una entidad, para lo cual a&amp;ntilde;adiremos el siguiente c&amp;oacute;digo al evento ContentLoaded del formulario de datos, en el que una vez obtenida la instancia de la entidad a editar, y bas&amp;aacute;ndonos en el valor de su propiedad Region, obtendremos del formulario el RadioButton correspondiente, para marcarlo mediante su propiedad IsChecked. N&amp;oacute;tese que puesto que algunos nombres de regi&amp;oacute;n est&amp;aacute;n formados por dos palabras, para componer el nombre del RadioButton, eliminamos los espacios en blanco mediante el m&amp;eacute;todo string.Replace.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; frmInvoices_ContentLoaded(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, DataFormContentLoadEventArgs e)
{
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (e.Mode == DataFormMode.Edit)
    {
        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
        Invoice oInvoiceActual = (Invoice)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.CurrentItem;
        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt; sRegion = oInvoiceActual.Region;
        RadioButton rbtRegion = (RadioButton)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;rbt&amp;quot;&lt;/span&gt; + sRegion.Replace(&lt;span style="color:#006080;"&gt;&amp;quot; &amp;quot;&lt;/span&gt;, &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty));
        rbtRegion.IsChecked = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_16.JPG" border="0" style="max-height:455px;max-width:409px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La otra parte de la funcionalidad que debemos implementar para estos controles corresponde al cambio en la selecci&amp;oacute;n del RadioButton mientras estamos en modo de edici&amp;oacute;n, ya que debemos actualizar la propiedad Region de la entidad Invoice que estamos editando con el valor del RadioButton seleccionado. Con tal finalidad, en la declaraci&amp;oacute;n de los controles en el c&amp;oacute;digo XAML hemos incluido la llamada al m&amp;eacute;todo rbtRegion_Checked, que actuar&amp;aacute; como manejador del evento Checked. La labor de dicho m&amp;eacute;todo consiste en comprobar si el RadioButton pulsado es distinto del valor de la propiedad Region de la entidad en edici&amp;oacute;n; en caso afirmativo actualizamos el valor de la propiedad.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; rbtRegion_Checked(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)
{
    Invoice oInvoiceActual = (Invoice)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.CurrentItem;
    RadioButton rbtRegion = (RadioButton)sender;

    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (oInvoiceActual.Region != rbtRegion.Content.ToString())
    {
        oInvoiceActual.Region = rbtRegion.Content.ToString();
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Y despu&amp;eacute;s de esta demostraci&amp;oacute;n de las capacidades de edici&amp;oacute;n del control RadioButton en el formulario de datos concluimos este art&amp;iacute;culo, en el cual hemos abordado una manera de potenciar las caracter&amp;iacute;sticas de edici&amp;oacute;n en el control DataForm, a trav&amp;eacute;s del uso de controles alternativos para los campos, en reemplazo del habitual TextBox, utilizado usualmente como control de edici&amp;oacute;n por defecto. Espero que os resulte de inter&amp;eacute;s.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=188001" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="Silverlight" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Silverlight/default.aspx" /><category term="WCF RIA Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/WCF+RIA+Services/default.aspx" /></entry><entry><title>Mejorando la experiencia de usuario en el control DataForm de Silverlight (2)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/01/24/mejorando-la-experiencia-de-usuario-en-el-control-dataform-de-silverlight-2.aspx" /><id>/blogs/lmblanco/archive/2011/01/24/mejorando-la-experiencia-de-usuario-en-el-control-dataform-de-silverlight-2.aspx</id><published>2011-01-24T17:52:00Z</published><updated>2011-01-24T17:52:00Z</updated><content type="html">&lt;p&gt;En la &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2011/01/23/mejorando-la-experiencia-de-usuario-en-el-control-dataform-de-silverlight-1.aspx"&gt;primera parte&lt;/a&gt; de este art&amp;iacute;culo, sentamos las bases para empezar a trabajar en la optimizaci&amp;oacute;n de la interfaz de usuario del DataForm construyendo el proyecto en Visual Studio 2010, la fuente de datos, y el formulario con una funcionalidad b&amp;aacute;sica para las plantillas de lectura y edici&amp;oacute;n. En esta segunda entrega ser&amp;aacute; cuando realmente comencemos con el proceso de mejora sobre los controles de edici&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;NumericUpDown para valores num&amp;eacute;ricos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Iniciamos nuestro periplo de optimizaciones por el campo Total del formulario. Se trata de un campo de tipo num&amp;eacute;rico que admite decimales, por lo que revisando la Barra de herramientas de Visual Studio 2010, en busca de un control m&amp;aacute;s adecuado para tratar estos valores, encontramos que NumericUpDown se adapta como un guante a este prop&amp;oacute;sito.&lt;/p&gt;
&lt;p&gt;&lt;img border="0" width="140" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_04.JPG" height="27" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Todo lo que tenemos que hacer es a&amp;ntilde;adir a la plantilla de edici&amp;oacute;n del DataForm un nuevo DataField que contenga un NumericUpDown. A la propiedad Value de este control le asignaremos la expresi&amp;oacute;n de enlace a datos que muestra el valor del campo. Adicionalmente, configuraremos el control para que admita decimales, el valor a incrementar cada vez que hagamos clic en los botones de aumentar/disminuir, y la alineaci&amp;oacute;n horizontal.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Importe:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:NumericUpDown&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Value&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=Total, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                           &lt;span style="color:#ff0000;"&gt;DecimalPlaces&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;2&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Increment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;0.5&amp;quot;&lt;/span&gt; 
                           &lt;span style="color:#ff0000;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img border="0" width="370" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_05.JPG" height="391" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;DatePicket y TimePicker. Combinando controles para editar campos de tipo datetime&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Cuando el control DataForm construye su interfaz de usuario predeterminada, genera controles DatePicker para editar los campos de tipo datetime. Esto generalmente funciona bien para la mayor&amp;iacute;a de las situaciones, pero &amp;iquest;qu&amp;eacute; ocurre si necesitamos editar la parte horaria correspondiente a este tipo de campo?&lt;/p&gt;
&lt;p&gt;Una posible soluci&amp;oacute;n consiste en utilizar un control TimePicker, el cual nos permitir&amp;aacute; editar esta informaci&amp;oacute;n. Por lo tanto, a&amp;ntilde;adiremos una copia del mismo a la plantilla EditTemplate del formulario de datos, situ&amp;aacute;ndolo al lado del control DatePicker ya existente, y encerrando ambos en un StackPanel.&lt;/p&gt;
&lt;p&gt;La propiedad utilizada por TimePicker para visualizar la hora es Value, a la que asignaremos la expresi&amp;oacute;n de enlace a datos que la unir&amp;aacute; con el campo InvoiceDate. En ambos controles, DatePicker y TimePicker, dicha expresi&amp;oacute;n de enlace es igual, siendo la maquinar&amp;iacute;a interna de cada control la encargada de editar la parte (fecha u hora) que le corresponda.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Fecha:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Orientation&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Horizontal&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;sdk:DatePicker&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;SelectedDate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceDate, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                        &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;110&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:TimePicker&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Value&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceDate, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                            &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;110&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Para modificar la parte de fecha del campo InvoiceDate con DatePicker, podemos editar directamente la caja de texto que contiene el valor de fecha, o hacer clic en el icono de este control que despliega el calendario.&lt;/p&gt;
&lt;p&gt;Respecto a la edici&amp;oacute;n de la parte horaria del campo con TimePicker, podemos igualmente, editar la caja de texto de este control escribiendo directamente el n&amp;uacute;mero, mediante las teclas de flecha arriba/abajo, o bien podemos hacer clic en el icono con forma de reloj, para desplegar una lista de horas.&lt;/p&gt;
&lt;p&gt;&lt;img border="0" width="409" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_06.JPG" height="392" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;AutoCompleteBox. Editar y seleccionar valores de una lista din&amp;aacute;mica&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En ciertas tablas de una base de datos pueden existir columnas cuyos valores se repiten a lo largo de los registros que componen la tabla, existiendo, adem&amp;aacute;s, la certeza de que en los nuevos registros a incorporar, tales valores se volver&amp;aacute;n a repetir, como es el caso del campo BillingCity de nuestra tabla de ejemplo Invoice.&lt;/p&gt;
&lt;p&gt;Para ayudar al usuario en la introducci&amp;oacute;n del contenido para este campo vamos a recurrir al control AutoCompleteBox, el cual, aparte de proporcionar la funcionalidad de una caja de texto, muestra de forma din&amp;aacute;mica una lista desplegable de sugerencias con los valores m&amp;aacute;s parecidos al contenido que la caja tenga en cada momento.&lt;/p&gt;
&lt;p&gt;&lt;img border="0" width="140" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_07.JPG" height="27" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El punto principal en la configuraci&amp;oacute;n de este control radica en la confecci&amp;oacute;n y asignaci&amp;oacute;n a su propiedad ItemsSource de la mencionada lista de valores con la que lo alimentamos. Existen diversas t&amp;eacute;cnicas para llevar a cabo esta tarea, algunas de las cuales explicaremos en los pr&amp;oacute;ximos apartados.&lt;/p&gt;
&lt;p&gt;En primer lugar a&amp;ntilde;adiremos a la plantilla EditTemplate del DataForm una copia de este control. La propiedad Text, al igual que en el TextBox, es la encargada de contener el valor de la caja de texto, por lo que le asignaremos la expresi&amp;oacute;n de enlace a datos que obtenga el valor de la propiedad correspondiente a la entidad de la colecci&amp;oacute;n.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Ciudad:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;sdk:AutoCompleteBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;acbBillingCity&amp;quot;&lt;/span&gt; 
                         &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingCity, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                         &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;120&amp;quot;&lt;/span&gt; 
                         &lt;span style="color:#ff0000;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;AutoCompleteBox. Creaci&amp;oacute;n de la lista utilizando la colecci&amp;oacute;n de entidades&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Cada vez que editemos un elemento de la colecci&amp;oacute;n de entidades asignada al DataForm, se activar&amp;aacute; la plantilla EditTemplate, cargando la entidad actual en los controles del formulario de datos. &lt;/p&gt;
&lt;p&gt;Tal acci&amp;oacute;n desencadenar&amp;aacute; el evento DataForm.ContentLoaded, en cuyo c&amp;oacute;digo comprobaremos el modo de edici&amp;oacute;n actualmente establecido en el formulario interrogando a la propiedad Mode (tipo enumerado DataFormMode) del par&amp;aacute;metro DataFormContentLoadEventArgs que recibe el evento. En el caso de que su valor sea Edit, obtendremos del DomainDataSource el objeto que representa al contexto de dominio (MusicaGestDomainContext), y mediante su colecci&amp;oacute;n de entidades Invoices, empleando una expresi&amp;oacute;n de LINQ, obtendremos todos los valores distintos correspondientes a la propiedad BillingCity de las entidades. A continuaci&amp;oacute;n recuperaremos el control AutoCompleteBox a&amp;ntilde;adido al formulario usando el m&amp;eacute;todo DataForm.FindNameInContent, asignando a la propiedad ItemsSource la lista de valores obtenida.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;/span&gt; . . . .
                  &lt;span style="color:#ff0000;"&gt;ContentLoaded&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices_ContentLoaded&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; ControlesDataForm.Web;
&lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; frmInvoices_ContentLoaded(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, DataFormContentLoadEventArgs e)
{
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (e.Mode == DataFormMode.Edit)
    {
        MusicaGestDomainContext oDomainContext = (MusicaGestDomainContext)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ddsInvoices.DomainContext;
        var oConsulta = (from oInvoice &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDomainContext.Invoices
                         select oInvoice.BillingCity).Distinct();
        AutoCompleteBox acbBillingCity = (AutoCompleteBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;acbBillingCity&amp;quot;&lt;/span&gt;);
        acbBillingCity.ItemsSource = oConsulta;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;En tiempo de ejecuci&amp;oacute;n, al comenzar a teclear un valor dentro de este control, se abrir&amp;aacute; debajo del mismo una lista desplegable compuesta por los valores que acabamos de cargar, pero de los que s&amp;oacute;lo se mostrar&amp;aacute;n los que comiencen por el mismo valor que hay contenido en la caja de texto del AutoCompleteBox.&lt;/p&gt;
&lt;p&gt;&lt;img border="0" width="407" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_08.JPG" height="391" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;AutoCompleteBox. Creaci&amp;oacute;n de la lista mediante un recurso&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Utilizando c&amp;oacute;digo XAML es posible crear declarativamente la lista de valores empleando un tipo ObjectCollection, dentro del cual incluiremos los elementos que formar&amp;aacute;n parte de la colecci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;Para declarar tipos de datos de .NET Framework tales como int, double, string, etc., debemos a&amp;ntilde;adir un atributo xmlns a la etiqueta UserControl de la p&amp;aacute;gina, que apunte al espacio de nombres System del ensamblado mscorlib. Una vez creada la colecci&amp;oacute;n (en la zona de recursos de la p&amp;aacute;gina XAML) asignaremos &amp;eacute;sta como un recurso est&amp;aacute;tico a la propiedad ItemsSource del AutoCompleteBox. El campo del formulario al que aplicaremos esta t&amp;eacute;cnica ser&amp;aacute; BillingState.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Class&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;ControlesDataForm.MainPage&amp;quot;&lt;/span&gt;
....    
    &lt;span style="color:#ff0000;"&gt;xmlns:System&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;clr-namespace:System;assembly=mscorlib&amp;quot;&lt;/span&gt;
....    
&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl.Resources&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:ObjectCollection&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Key&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;colEstados&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;AB&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;AZ&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;BC&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;CA&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;DF&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;Dublin&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;FL&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;System:String&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
             &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:ObjectCollection&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl.Resources&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;/span&gt;
        &amp;amp;&lt;span style="color:#ff0000;"&gt;lt&lt;/span&gt;;!&lt;span style="color:#ff0000;"&gt;--&lt;/span&gt;....&lt;span style="color:#ff0000;"&gt;--&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.EditTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Estado o Provincia:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;sdk:AutoCompleteBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingState, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                                     &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;100&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt;
                                     &lt;span style="color:#ff0000;"&gt;ItemsSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{StaticResource colEstados}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img border="0" width="409" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_09.JPG" height="393" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;DomainUpDown. Edici&amp;oacute;n y navegaci&amp;oacute;n entre un conjunto de valores&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;El objetivo de DomainUpDown, al igual que AutoCompleteBox, consiste en seleccionar un valor de una lista (dominio de valores), aunque la diferencia en este caso reside en que dicha lista no se despliega, sino que nos movemos por ella mediante sus controles de desplazamiento.&lt;/p&gt;
&lt;p&gt;&lt;img border="0" width="133" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_10.JPG" height="27" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El modo de creaci&amp;oacute;n y configuraci&amp;oacute;n de este control tambi&amp;eacute;n es muy similar al de AutoCompleteBox, siendo ItemsSource la propiedad a la que tendremos que asignar la lista de valores. En nuestro ejemplo emplearemos este control para editar el campo BillingCountry, creando la lista de elementos mediante LINQ, como ya vimos anteriormente. En este caso aplicaremos tambi&amp;eacute;n la part&amp;iacute;cula orderby a la expresi&amp;oacute;n LINQ para obtener los valores ordenados.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Pa&amp;iacute;s:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DomainUpDown&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;dudBillingCountry&amp;quot;&lt;/span&gt; 
                          &lt;span style="color:#ff0000;"&gt;Value&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingCountry, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                          &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;120&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; frmInvoices_ContentLoaded(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, DataFormContentLoadEventArgs e)
{
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (e.Mode == DataFormMode.Edit)
    {
        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
        var qryConsulta = (from oInvoice &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDomainContext.Invoices
                           orderby oInvoice.BillingCountry
                           select oInvoice.BillingCountry).Distinct();

        DomainUpDown dudBillingCountry = (DomainUpDown)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;dudBillingCountry&amp;quot;&lt;/span&gt;);
        dudBillingCountry.ItemsSource = qryConsulta;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img border="0" width="412" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_11.JPG" height="394" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El conjunto de valores asignado a un control DomainUpDown inicialmente es cerrado. Esto quiere decir que si escribimos un valor en la caja de texto que no est&amp;eacute; en la lista asignada al control, y pulsamos la tecla Intro o cambiamos el foco a otro control del formulario, dicho valor ser&amp;aacute; rechazado, volviendo la zona de edici&amp;oacute;n a recuperar su valor original; por lo que a priori, los &amp;uacute;nicos valores admisibles son los existentes en la propiedad ItemsSource.&lt;/p&gt;
&lt;p&gt;Una forma de alterar este comportamiento del control pasa por asignar a su propiedad InvalidInputAction el valor UseFallbackItem, y en la propiedad FallbackItem un valor igual a uno de los elementos de la lista de valores asignada al control. De esta forma, si el usuario introduce un valor incorrecto, se asignar&amp;aacute; como valor por defecto el existente en FallbackItem.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DomainUpDown&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;dudBillingCountry&amp;quot;&lt;/span&gt; 
                      &lt;span style="color:#ff0000;"&gt;Value&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingCountry, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                      &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;120&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt; 
                      &lt;span style="color:#ff0000;"&gt;InvalidInputAction&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;UseFallbackItem&amp;quot;&lt;/span&gt; 
                      &lt;span style="color:#ff0000;"&gt;FallbackItem&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Germany&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Otra t&amp;eacute;cnica consiste en asignar a la propiedad InvalidInputAction el valor TextBoxCannotLoseFocus, lo que mantiene el foco en el control mientras el usuario no introduzca un valor que concuerde con alguno de los existentes en la colecci&amp;oacute;n asignada a ItemsSource.&lt;/p&gt;
&lt;p&gt;Pero supongamos que el usuario necesita que el valor tecleado en el control sea a&amp;ntilde;adido a su lista de valores en el caso de que no exista. En este tipo de situaci&amp;oacute;n, el control DomainUpDown desencadena el evento ParseError, de manera que si escribimos un manipulador para dicho evento podemos adaptar el comportamiento del control a nuestras necesidades.&lt;/p&gt;
&lt;p&gt;En el c&amp;oacute;digo de este evento obtendremos la instancia del control DomainUpDown a trav&amp;eacute;s del par&amp;aacute;metro sender que el manipulador recibe, y acto seguido recuperaremos la lista de valores mediante su propiedad Items, volc&amp;aacute;ndola a un tipo List&amp;lt;object&amp;gt;.&lt;/p&gt;
&lt;p&gt;A&amp;ntilde;adiremos al objeto List el valor que el usuario ha escrito en la caja de texto, que se encuentra disponible en la propiedad Text del par&amp;aacute;metro UpDownParseErrorEventArgs que recibe el manipulador del evento. Finalmente ordenaremos la lista llamando a su m&amp;eacute;todo OrderBy, asign&amp;aacute;ndola de nuevo a la propiedad ItemsSource del control.&lt;/p&gt;
&lt;p&gt;Al producirse este evento se vac&amp;iacute;a la caja de texto del DomainUpDown, por lo que volveremos a asignarle a su propiedad Value el valor que el usuario hab&amp;iacute;a tecleado, que como ya hemos indicado, se encuentra en la propiedad UpDownParseErrorEventArgs.Text.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Pa&amp;iacute;s:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DomainUpDown&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;dudBillingCountry&amp;quot;&lt;/span&gt; 
                          &lt;span style="color:#ff0000;"&gt;Value&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingCountry, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                          &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;120&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt; 
                          &lt;span style="color:#ff0000;"&gt;ParseError&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;dudBillingCountry_ParseError&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; dudBillingCountry_ParseError(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, UpDownParseErrorEventArgs e)
{
    DomainUpDown dudBillingCountry = (DomainUpDown)sender;
    List&amp;lt;&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt;&amp;gt; lstPaises = dudBillingCountry.Items.ToList();
    lstPaises.Add(e.Text);
    dudBillingCountry.ItemsSource = lstPaises.OrderBy(sPais =&amp;gt; sPais);
    dudBillingCountry.Value = e.Text;
    e.Handled = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Con este control llegamos al final de la segunda parte del art&amp;iacute;culo, en el que hemos abordado varias maneras de mejorar la forma en que podemos editar los valores de los campos de un DataForm. En la tercera parte, que concluye la serie, continuaremos mostrando controles adicionales, que consigan hacer que la edici&amp;oacute;n de los campos por parte de nuestros usuarios, sea una labor un poco m&amp;aacute;s f&amp;aacute;cil y grata. En el siguiente &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201012/DataFormUXZip.txt"&gt;enlace&lt;/a&gt; tenemos disponible el proyecto de ejemplo&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=187856" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="Silverlight" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Silverlight/default.aspx" /><category term="WCF RIA Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/WCF+RIA+Services/default.aspx" /></entry><entry><title>Mejorando la experiencia de usuario en el control DataForm de Silverlight (1)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2011/01/23/mejorando-la-experiencia-de-usuario-en-el-control-dataform-de-silverlight-1.aspx" /><id>/blogs/lmblanco/archive/2011/01/23/mejorando-la-experiencia-de-usuario-en-el-control-dataform-de-silverlight-1.aspx</id><published>2011-01-23T15:06:00Z</published><updated>2011-01-23T15:06:00Z</updated><content type="html">&lt;p&gt;En el &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2010/10/13/dataform-edittemplate-y-newitemtemplate-edici-243-n-de-datos-en-silverlight-mediante-plantillas-1.aspx"&gt;art&amp;iacute;culo&lt;/a&gt; dedicado a la edici&amp;oacute;n de datos con plantillas en el DataForm, apunt&amp;aacute;bamos la posibilidad de mejorar la interfaz de usuario para este control, debido a que los controles de edici&amp;oacute;n que se proporcionan por defecto pueden no ser los m&amp;aacute;s indicados en todos los escenarios a desarrollar.&lt;/p&gt;
&lt;p&gt;Las caracter&amp;iacute;sticas de los valores a manipular hacen que en ciertas situaciones, un TextBox, por ejemplo, no resulte suficiente si adem&amp;aacute;s de escribir el valor del campo queremos ofrecer al usuario una lista de posibles valores para evitar que tenga que teclearlos.&lt;/p&gt;
&lt;p&gt;Por tales razones, a trav&amp;eacute;s de las diversas entregas que componen este art&amp;iacute;culo, nos dedicaremos a intentar optimizar la experiencia de usuario en algunos aspectos susceptibles de ser mejorados con respecto al comportamiento predeterminado que ofrece el DataForm. El c&amp;oacute;digo fuente del ejemplo que desarrollaremos puede descargarse &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201101/DataFormUXZip.txt"&gt;aqu&amp;iacute;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Elaboraci&amp;oacute;n de la fuente de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Al igual que en otros art&amp;iacute;culos, el primer paso fundamental consiste en preparar un conjunto de datos de prueba. Como en otras ocasiones, nuestro punto de partida ser&amp;aacute; la base de datos Chinook, que podemos descargar desde &lt;a href="http://chinookdatabase.codeplex.com/"&gt;CodePlex&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Empleando, con algunas variaciones, los datos de las tablas Invoice y Customer pertenecientes a la base de datos Chinook, crearemos sendas tablas de igual nombre en una nueva base de datos que llamaremos MusicaGest, utilizando las sentencias SQL del siguiente script.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;DATABASE&lt;/span&gt; MusicaGest
&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;

&lt;span style="color:#0000ff;"&gt;USE&lt;/span&gt; MusicaGest
&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;

&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Invoice
(
    InvoiceId &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,
    CustomerId &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,
    InvoiceDate datetime &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,
    BillingAddress &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(70) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,
    BillingCity &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(50) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,
    BillingState &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(50) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,
    BillingCountry &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(50) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,
    Region &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(50) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,
    Total &lt;span style="color:#0000ff;"&gt;numeric&lt;/span&gt;(10, 2) &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,
    FirstInvoice &lt;span style="color:#0000ff;"&gt;bit&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,
    &lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Invoice &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (InvoiceId &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;)
)
&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;

INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Invoice
&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; InvoiceId,CustomerId,InvoiceDate,
BillingAddress,BillingCity,BillingState,BillingCountry,
&lt;span style="color:#0000ff;"&gt;CASE&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; BillingCountry &lt;span style="color:#0000ff;"&gt;IN&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;Austria&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Belgium&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Czech Republic&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Denmark&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Finland&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;France&amp;#39;&lt;/span&gt;,
        &lt;span style="color:#006080;"&gt;&amp;#39;Germany&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Hungary&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Ireland&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Italy&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Netherlands&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Norway&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Poland&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Portugal&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Spain&amp;#39;&lt;/span&gt;,
        &lt;span style="color:#006080;"&gt;&amp;#39;Sweden&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;United Kingdom&amp;#39;&lt;/span&gt;) &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;Europe&amp;#39;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; BillingCountry &lt;span style="color:#0000ff;"&gt;IN&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;Argentina&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Brazil&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;Chile&amp;#39;&lt;/span&gt;) &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;South America&amp;#39;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; BillingCountry &lt;span style="color:#0000ff;"&gt;IN&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;Canada&amp;#39;&lt;/span&gt;,&lt;span style="color:#006080;"&gt;&amp;#39;USA&amp;#39;&lt;/span&gt;) &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;North America&amp;#39;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; BillingCountry &lt;span style="color:#0000ff;"&gt;IN&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;Australia&amp;#39;&lt;/span&gt;) &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;Oceania&amp;#39;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;WHEN&lt;/span&gt; BillingCountry &lt;span style="color:#0000ff;"&gt;IN&lt;/span&gt; (&lt;span style="color:#006080;"&gt;&amp;#39;India&amp;#39;&lt;/span&gt;) &lt;span style="color:#0000ff;"&gt;THEN&lt;/span&gt; &lt;span style="color:#006080;"&gt;&amp;#39;Asia&amp;#39;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;END&lt;/span&gt;,
Total,
(CustomerId % 2)
&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Chinook.dbo.Invoice
&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;

&lt;span style="color:#0000ff;"&gt;CREATE&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;TABLE&lt;/span&gt; Customer
(
    CustomerId &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,
    Name &lt;span style="color:#0000ff;"&gt;varchar&lt;/span&gt;(61) &lt;span style="color:#0000ff;"&gt;NOT&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;NULL&lt;/span&gt;,
    &lt;span style="color:#0000ff;"&gt;CONSTRAINT&lt;/span&gt; PK_Customer &lt;span style="color:#0000ff;"&gt;PRIMARY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;KEY&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;CLUSTERED&lt;/span&gt; (CustomerId &lt;span style="color:#0000ff;"&gt;ASC&lt;/span&gt;)
)
&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;

INSERT &lt;span style="color:#0000ff;"&gt;INTO&lt;/span&gt; Customer
&lt;span style="color:#0000ff;"&gt;SELECT&lt;/span&gt; CustomerId, FirstName + &lt;span style="color:#006080;"&gt;&amp;#39; &amp;#39;&lt;/span&gt; + LastName &lt;span style="color:#0000ff;"&gt;AS&lt;/span&gt; CustomerName 
&lt;span style="color:#0000ff;"&gt;FROM&lt;/span&gt; Chinook.dbo.Customer
&lt;span style="color:#0000ff;"&gt;GO&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Creaci&amp;oacute;n del proyecto en Visual Studio 2010&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;De igual forma que en otros art&amp;iacute;culos dedicados al DataForm, iniciaremos Visual Studio 2010 y crearemos un nuevo proyecto de tipo Silverlight con el nombre DataFormUX, en el que activaremos WCF RIA Services.&lt;/p&gt;
&lt;p&gt;Los primeros pasos que daremos en el desarrollo de este proyecto ser&amp;aacute;n la creaci&amp;oacute;n de un modelo de datos (ADO .NET Data Model) con el nombre MusicaGestModel, al que a&amp;ntilde;adiremos las tablas Invoice y Customer, que ser&amp;aacute;n convertidas en entidades dentro del modelo. Tambi&amp;eacute;n agregaremos un servicio de dominio (Domain Service) con el nombre MusicaGestDomainService que contendr&amp;aacute; las operaciones de manipulaci&amp;oacute;n de dichas entidades. Consulte el lector el siguiente &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2010/06/20/validaci-243-n-en-acci-243-n-con-el-control-dataform-de-silverlight-1.aspx"&gt;art&amp;iacute;culo&lt;/a&gt; para un mayor detalle acerca de la creaci&amp;oacute;n del modelo de datos y del servicio de dominio.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;El formulario de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Nuestro siguiente paso consistir&amp;aacute; en escribir, dentro de la p&amp;aacute;gina MainPage.xaml, el c&amp;oacute;digo necesario para crear un DataForm y su fuente de datos correspondiente, representada por un control DomainDataSource. &lt;/p&gt;
&lt;p&gt;&lt;img border="0" width="157" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_01.JPG" height="28" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;Aprovecharemos igualmente para incluir sendas plantillas ReadOnlyTemplate y EditTemplate, con las que respectivamente presentaremos y editaremos los elementos de la colecci&amp;oacute;n de entidades conectada al formulario de datos.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;p&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Class&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;DataFormUX.MainPage&amp;quot;&lt;/span&gt;
    &lt;span style="color:#ff0000;"&gt;xmlns:riaControls&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices&amp;quot;&lt;/span&gt;    &lt;br /&gt;    &lt;span style="color:#ff0000;"&gt;xmlns:toolkit&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit&amp;quot;&lt;/span&gt;  
    &lt;span style="color:#ff0000;"&gt;xmlns:sdk&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk&amp;quot;&lt;/span&gt;  
    &lt;span style="color:#ff0000;"&gt;xmlns:domainctx&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;clr-namespace:DataFormUX.Web&amp;quot;&lt;br /&gt;&lt;/span&gt;....
&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl.Resources&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;        
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Style&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;TargetType&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;TextBox&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Setter&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Property&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;HorizontalAlignment&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Value&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Style&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl.Resources&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;ddsInvoices&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;QueryName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;GetInvoices&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.DomainContext&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;domainctx:MusicaGestDomainContext&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.DomainContext&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;Margin&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;10&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;ItemsSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding ElementName=ddsInvoices, Path=Data}&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;AutoEdit&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt;
                    &lt;span style="color:#ff0000;"&gt;AutoCommit&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.ReadOnlyTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo factura:&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;N&amp;uacute;mero identificador de la factura&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceId, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo cliente:&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Identificador del cliente&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=CustomerId, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Fecha:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceDate, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Direcci&amp;oacute;n:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingAddress, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Ciudad:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingCity, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Estado o Provincia:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingState, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Pa&amp;iacute;s:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingCountry, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Region:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=Region, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Importe:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=Total, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Primera factura?:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=FirstInvoice, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.ReadOnlyTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.EditTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo factura:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceId, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;40&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo Cliente:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=CustomerId, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;40&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Fecha:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;sdk:DatePicker&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;SelectedDate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceDate, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                        &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;110&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Direcci&amp;oacute;n:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingAddress, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;150&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Ciudad:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingCity, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;120&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Estado o Provincia:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingState, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;100&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Pa&amp;iacute;s:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingCountry, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;80&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Regi&amp;oacute;n:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=Region, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;100&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Importe:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=Total, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Primera factura?:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;CheckBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;IsChecked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=FirstInvoice, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.EditTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/p&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Comenzando con la mejora&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Llegados a este punto habremos logrado un formulario de datos con una interfaz de usuario muy similar a la que el DataForm hubiera generado autom&amp;aacute;ticamente, pero en la que el control TextBox queda algo escaso de funcionalidad para la edici&amp;oacute;n de los valores de ciertos campos.&lt;/p&gt;
&lt;p&gt;&lt;img border="0" width="726" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_02.JPG" height="575" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A partir de la segunda entrega de este art&amp;iacute;culo propondremos soluciones puntuales para cada uno de los campos que consideremos mejorables, sustituyendo el control TextBox inicial por otro m&amp;aacute;s adecuado para los valores que el usuario deba editar. Sin embargo, antes de entrar en el desarrollo de tales funcionalidades, modificaremos en primer lugar la plantilla ReadOnlyTemplate, de forma que, por un lado, adem&amp;aacute;s del c&amp;oacute;digo del cliente (campo CustomerId) tambi&amp;eacute;n se visualice el nombre (campo CustomerName de la tabla Customers); mientras que por otra parte, haremos que el campo InvoiceDate muestre la fecha con un formato m&amp;aacute;s adecuado. Toda esta funcionalidad la lograremos utilizando convertidores de tipo, como vimos en los art&amp;iacute;culos dedicados a las &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2010/08/27/plantillas-de-presentaci-243-n-de-datos-en-el-control-dataform-de-silverlight-y-2.aspx"&gt;plantillas de presentaci&amp;oacute;n en el DataForm&lt;/a&gt; y &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2008/10/13/reutilizar-un-convertidor-de-tipo-en-varias-columnas-del-control-datagrid-de-silverlight.aspx"&gt;uso de convertidores en el DataGrid&lt;/a&gt;, publicados anteriormente en este blog.&lt;/p&gt;
&lt;p&gt;Primeramente a&amp;ntilde;adiremos a la p&amp;aacute;gina XAML un nuevo control DomainDataSource que obtenga la colecci&amp;oacute;n de entidades Customer.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;ddsCustomers&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;QueryName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;GetCustomers&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.DomainContext&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;domainctx:MusicaGestDomainContext&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.DomainContext&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Background&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;SkyBlue&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;br /&gt;&lt;/span&gt;....
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El c&amp;oacute;digo de los convertidores lo escribiremos en un archivo con el nombre Convertidores.cs, que agregaremos al proyecto Silverlight de la soluci&amp;oacute;n que estamos desarrollando. Dentro de este archivo crearemos las clases FechaConvertidor y CustomerConvertidor, que utilizaremos respectivamente para formatear la fecha de la factura y obtener el nombre del cliente.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System;
&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Collections.Generic;
&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Linq;
&lt;span style="color:#0000ff;"&gt;using&lt;/span&gt; System.Windows.Data;

&lt;span style="color:#0000ff;"&gt;namespace&lt;/span&gt; DataFormUX.Web
{
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; FechaConvertidor : IValueConverter
    {
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Convert(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;, Type targetType, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; parameter, System.Globalization.CultureInfo culture)
        {
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; ((DateTime)&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;).ToString(&lt;span style="color:#006080;"&gt;&amp;quot;dd \\de MMMM \\de yyyy; HH:mm&amp;quot;&lt;/span&gt;);
        }

        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; ConvertBack(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;, Type targetType, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; parameter, System.Globalization.CultureInfo culture)
        {
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
        }
    }

    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; CustomerConvertidor : IValueConverter
    {
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Convert(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;, Type targetType, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; parameter, System.Globalization.CultureInfo culture)
        {
            MusicaGestDomainContext oDomainContext = (MusicaGestDomainContext)((MainPage)App.Current.RootVisual).ddsCustomers.DomainContext;
            Customer oCustomer;

            &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (oDomainContext.Customers.Count &amp;gt; 0)
            {
                oCustomer = (from oCust &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; oDomainContext.Customers
                             &lt;span style="color:#0000ff;"&gt;where&lt;/span&gt; oCust.CustomerId == (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt;)&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;
                             select oCust).Single();
            }
            &lt;span style="color:#0000ff;"&gt;else&lt;/span&gt;
            {
                oCustomer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Customer() { CustomerId = -1, CustomerName = &lt;span style="color:#006080;"&gt;&amp;quot;--&amp;quot;&lt;/span&gt; };
            }
            
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; oCustomer.CustomerName;
        }

        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; ConvertBack(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;, Type targetType, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; parameter, System.Globalization.CultureInfo culture)
        {
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
        }
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Centr&amp;aacute;ndonos en la clase CustomerConvertidor, la t&amp;eacute;cnica que hemos empleado para obtener el nombre del cliente consiste en tomar el objeto App, que representa a la aplicaci&amp;oacute;n en ejecuci&amp;oacute;n (deriva de la clase Application), y a trav&amp;eacute;s de sus propiedades, acceder al DomainDataSource ddsCustomers situado en el objeto MainPage, que deriva de UserControl y representa a la p&amp;aacute;gina XAML en la que construimos la interfaz de usuario.&lt;/p&gt;
&lt;p&gt;Desde ddsCustomers obtenemos el contexto de dominio (propiedad DomainContext), y comprobamos que la colecci&amp;oacute;n de entidades contiene elementos interrogando a su propiedad Count, ya que hemos detectado que, aleatoriamente, este DomainDataSource tarda un cierto tiempo en cargarse, y en algunas ocasiones, a la hora de mostrar la primera entidad en el DataForm, todav&amp;iacute;a se encuentra vac&amp;iacute;o.&lt;/p&gt;
&lt;p&gt;En el caso de que ddsCustomers contenga valores, para obtener el objeto Customer adecuado utilizamos una expresi&amp;oacute;n LINQ, en la que empleamos el par&amp;aacute;metro value del m&amp;eacute;todo Convert, que contiene el valor del campo CustomerId. Si ddsCustomers no tiene elementos, creamos un objeto Customer sin nombre. Como &amp;uacute;ltimo paso devolvemos la propiedad CustomerName del objeto Customer como valor de retorno, la cual ser&amp;aacute; visualizada en un campo de la plantilla ReadOnlyTemplate del DataForm. Previamente, tendremos que haber instanciado los convertidores en la zona de recursos de la p&amp;aacute;gina XAML.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="font-size:10pt;margin:0em;overflow:visible;width:100%;color:black;line-height:12pt;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;background-color:#f4f4f4;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl.Resources&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;domainctx:FechaConvertidor&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Key&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;cnvFechaConvertidor&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;domainctx:CustomerConvertidor&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Key&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;cnvCustomerConvertidor&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl.Resources&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;/span&gt; 
....
&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.ReadOnlyTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Nombre cliente:&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Nombre del cliente&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=CustomerId, Mode=OneWay, Converter={StaticResource cnvCustomerConvertidor}}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Fecha:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceDate, Mode=OneWay, Converter={StaticResource cnvFechaConvertidor}}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Despu&amp;eacute;s de haber realizado estas modificaciones, el DataForm en modo de lectura mostrar&amp;aacute; las mejoras aplicadas, como vemos en la siguiente figura.&lt;/p&gt;
&lt;p&gt;&lt;img border="0" width="391" src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201101/MejorandoExperienciaUsuarioControlDataFormSilverlight_5F00_03.JPG" height="576" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Y con esta mejora sobre la plantilla de lectura del DataForm termina la primera parte del art&amp;iacute;culo. En la siguiente entrega comenzaremos con las optimizaciones a nivel de la plantilla de edici&amp;oacute;n del formulario, a trav&amp;eacute;s del uso de controles alternativos al TextBox.&amp;nbsp;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=187789" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="Silverlight" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Silverlight/default.aspx" /><category term="WCF RIA Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/WCF+RIA+Services/default.aspx" /></entry><entry><title>DataForm EditTemplate y NewItemTemplate. Edición de datos en Silverlight mediante plantillas (y 2)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2010/10/14/dataform-edittemplate-y-newitemtemplate-edici-243-n-de-datos-en-silverlight-mediante-plantillas-y-2.aspx" /><id>/blogs/lmblanco/archive/2010/10/14/dataform-edittemplate-y-newitemtemplate-edici-243-n-de-datos-en-silverlight-mediante-plantillas-y-2.aspx</id><published>2010-10-14T21:05:00Z</published><updated>2010-10-14T21:05:00Z</updated><content type="html">&lt;p&gt;Despu&amp;eacute;s de la introducci&amp;oacute;n a la plantilla EditTemplate del control DataForm realizada en la primera parte, en esta segunda entrega trataremos algunos aspectos adicionales de dicha plantilla, as&amp;iacute; como la inserci&amp;oacute;n de nuevos datos utilizando la plantilla NewItemTemplate, proporcionada tambi&amp;eacute;n por este control. Al igual que en la anterior entrega, el c&amp;oacute;digo fuente de los ejemplos est&amp;aacute; disponible en este &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201010/PlantillasEdicionZip.txt"&gt;enlace&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Deshabilitar el modo de edici&amp;oacute;n autom&amp;aacute;tica&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Cada vez que ejecutamos el formulario habremos comprobado que podemos editar directamente los campos de la entidad en la que nos posicionamos al navegar por la colecci&amp;oacute;n de entidades. Ello es debido a que la propiedad AutoEdit del DataForm tiene el valor true por defecto. Si queremos que sea el usuario quien decida cu&amp;aacute;ndo quiere activar el modo de edici&amp;oacute;n tendremos que asignar el valor false a dicha propiedad.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;/span&gt; 
                  &lt;span style="color:#ff0000;"&gt;ItemsSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding ElementName=ddsInvoices, Path=Data}&amp;quot;&lt;/span&gt; 
                  &lt;span style="color:#ff0000;"&gt;Margin&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;5&amp;quot;&lt;/span&gt; 
                  &lt;span style="color:#ff0000;"&gt;Header&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Edici&amp;oacute;n de facturas&amp;quot;&lt;/span&gt; 
                  &lt;span style="color:#ff0000;"&gt;AutoEdit&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;De esta manera, el DataForm ofrecer&amp;aacute; inicialmente los campos en modo de lectura, incorporando un nuevo bot&amp;oacute;n en la barra de herramientas con la imagen de un lapicero. Al hacer clic en dicho bot&amp;oacute;n, el estado de los controles pasar&amp;aacute; de s&amp;oacute;lo lectura a edici&amp;oacute;n. Para grabar los cambios realizados en los campos tan s&amp;oacute;lo es necesario hacer clic en cualquiera de los botones de navegaci&amp;oacute;n para movernos a otra entidad, o bien hacer clic en el bot&amp;oacute;n Cancel para deshacer los cambios y devolver los campos a sus valores originales.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas2_5F00_09.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;La propiedad AutoEdit y la plantilla ReadOnlyTemplate&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si pretendemos utilizar simult&amp;aacute;neamente en el DataForm una plantilla EditTemplate y otra ReadOnlyTemplate, hemos de tener en cuenta que mientras que la propiedad AutoEdit tenga el valor true, el DataForm har&amp;aacute; caso omiso de la plantilla ReadOnlyTemplate, utilizando solamente la plantilla de edici&amp;oacute;n. Para solucionar este comportamiento bastar&amp;aacute; con asignar false a la propiedad AutoEdit como vemos a continuaci&amp;oacute;n.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;ItemsSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding ElementName=ddsInvoices, Path=Data}&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;Margin&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;5&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;Header&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Edici&amp;oacute;n de facturas&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;AutoEdit&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.ReadOnlyTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo factura:&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;N&amp;uacute;mero identificador de la factura&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceId, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo cliente:&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Identificador del cliente&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=CustomerId, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Fecha:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceDate, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Direcci&amp;oacute;n:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingAddress, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Ciudad:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingCity, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Pa&amp;iacute;s:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingCountry, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Importe:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=Total, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Primera factura?:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=FirstInvoice, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.ReadOnlyTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.EditTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.EditTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas2_5F00_10.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Confirmando manualmente los cambios realizados a la entidad&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Despu&amp;eacute;s de editar uno o varios campos del formulario, para que dichos cambios queden guardados en la colecci&amp;oacute;n de entidades asociada al DataForm, nos desplazaremos a otra entidad de la colecci&amp;oacute;n utilizando los botones de navegaci&amp;oacute;n de la barra de herramientas.&lt;/p&gt;
&lt;p&gt;Pero en algunos casos puede resultar interesante obligar al usuario a aceptar de forma expl&amp;iacute;cita tales modificaciones. Esto lo podemos conseguir asignando el valor false a la propiedad AutoCommit del control DataForm, la cual contiene true por defecto.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;/span&gt; 
                  &lt;span style="color:#ff0000;"&gt;ItemsSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding ElementName=ddsInvoices, Path=Data}&amp;quot;&lt;/span&gt; 
                  &lt;span style="color:#ff0000;"&gt;Margin&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;5&amp;quot;&lt;/span&gt; 
                  &lt;span style="color:#ff0000;"&gt;Header&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Edici&amp;oacute;n de facturas&amp;quot;&lt;/span&gt; 
                  &lt;span style="color:#ff0000;"&gt;AutoEdit&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt; 
                  &lt;span style="color:#ff0000;"&gt;AutoCommit&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Una vez hecha esta asignaci&amp;oacute;n, cada vez que editemos una entidad del DataForm se mostrar&amp;aacute; el bot&amp;oacute;n OK, que utilizaremos para aceptar los cambios que hayamos efectuado en los campos del formulario.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas2_5F00_11.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;El bot&amp;oacute;n OK estar&amp;aacute; inicialmente deshabilitado y no se habilitar&amp;aacute; hasta que no hagamos cambios en alguno de los campos del formulario. A partir del momento en el que este bot&amp;oacute;n est&amp;eacute; disponible, los botones de la barra de herramientas se deshabilitar&amp;aacute;n, con lo que el usuario estar&amp;aacute; obligado a aceptar o cancelar haciendo clic, respectivamente, en OK o Cancel.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas2_5F00_12.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una de las ventajas de confirmar la edici&amp;oacute;n de campos mediante el bot&amp;oacute;n OK radica en que una vez pulsado dicho bot&amp;oacute;n seguiremos posicionados en la misma entidad que est&amp;aacute;bamos editando. Recordemos que cuando s&amp;oacute;lo disponemos del bot&amp;oacute;n Cancel tenemos que movernos a otra entidad de la colecci&amp;oacute;n para hacer efectivos los cambios.&lt;/p&gt;
&lt;p&gt;Como apunte est&amp;eacute;tico adicional conviene saber que las propiedades CommitButtonContent y CancelButtonContent permiten asignar a estos botones un t&amp;iacute;tulo distinto del que se ofrece por defecto.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;ItemsSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding ElementName=ddsInvoices, Path=Data}&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;Margin&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;5&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;Header&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Edici&amp;oacute;n de facturas&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;AutoEdit&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;AutoCommit&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;CommitButtonContent&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Aceptar cambios&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;CancelButtonContent&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Salir de edici&amp;oacute;n&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas2_5F00_13.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Borrar una entidad de la colecci&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Podemos utilizar el bot&amp;oacute;n Borrar de la barra de herramientas para eliminar la entidad actual sobre la que est&amp;aacute; posicionado el DataForm, aunque debemos tener precauci&amp;oacute;n, ya que el borrado se realiza sin pedir confirmaci&amp;oacute;n al usuario.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas2_5F00_14.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Si queremos prevenir borrados accidentales crearemos un manipulador para el evento DeletingItem, que se producir&amp;aacute; durante la solicitud de borrado de un elemento de la colecci&amp;oacute;n del formulario, lo cual nos permite anular la operaci&amp;oacute;n de borrado asignando el valor true a la propiedad Cancel del tipo CancelEventArgs que este manipulador recibe como par&amp;aacute;metro.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;/span&gt; 
                  &amp;lt;&lt;span style="color:#ff0000;"&gt;--&lt;/span&gt;....&lt;span style="color:#ff0000;"&gt;--&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                  DeletingItem=&amp;quot;frmInvoices_DeletingItem&amp;quot;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; frmInvoices_DeletingItem(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, System.ComponentModel.CancelEventArgs e)
{
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (MessageBox.Show(&lt;span style="color:#006080;"&gt;&amp;quot;&amp;iquest;Borrar la factura?&amp;quot;&lt;/span&gt;, &lt;span style="color:#006080;"&gt;&amp;quot;Atenci&amp;oacute;n&amp;quot;&lt;/span&gt;, MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
    {
        e.Cancel = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
    }
}
&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas2_5F00_15.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;NewItemTemplate. A&amp;ntilde;adiendo nuevos elementos al DataForm&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Gracias a la plantilla NewItemTemplate podemos crear una interfaz de usuario espec&amp;iacute;fica para los casos en que tengamos que agregar nuevos elementos a la colecci&amp;oacute;n de entidades del formulario haciendo clic en el bot&amp;oacute;n A&amp;ntilde;adir.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas2_5F00_16.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;El siguiente bloque de c&amp;oacute;digo XAML muestra el modo de declaraci&amp;oacute;n de esta plantilla.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; ....&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.NewItemTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.NewItemTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;La carencia de esta plantilla no significa que en el formulario no podamos a&amp;ntilde;adir nuevas entidades, ya que en tal situaci&amp;oacute;n, el DataForm autom&amp;aacute;ticamente hace uso de la plantilla EditTemplate, utiliz&amp;aacute;ndola como plantilla de inserci&amp;oacute;n.&lt;/p&gt;
&lt;p&gt;No obstante, la inserci&amp;oacute;n es una operaci&amp;oacute;n de edici&amp;oacute;n con ciertas particularidades, que no siempre van a poder ser sustituidas directamente mediante la plantilla EditTemplate.&lt;/p&gt;
&lt;p&gt;Por ejemplo, supongamos que en nuestra aplicaci&amp;oacute;n, a la hora de crear una nueva factura, los campos del DataForm deben cumplir con una serie de pautas y restricciones, las cuales describiremos en los siguientes apartados, aportando una soluci&amp;oacute;n para cada una de ellas.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;InvoiceId&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;La edici&amp;oacute;n de este campo estar&amp;aacute; restringida en la creaci&amp;oacute;n de una factura, ya que como hemos comentado anteriormente, estamos ante un valor que genera autom&amp;aacute;ticamente el motor de datos, por lo que resulta innecesaria su introducci&amp;oacute;n manual por parte del usuario.&lt;/p&gt;
&lt;p&gt;Por tal motivo, no incluiremos en la plantilla NewItemTemplate un control para editar este campo.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;InvoiceDate&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Este campo tampoco podr&amp;aacute; ser editado por el usuario, ya que tomar&amp;aacute; su valor de la fecha del sistema. Sin embargo, a diferencia del anterior, su valor s&amp;iacute; tendr&amp;aacute; que ser visualizado.&lt;/p&gt;
&lt;p&gt;La forma de resolver este problema consistir&amp;aacute;, por una parte, en asignar el valor false a la propiedad IsEnabled del DataField que utilizaremos en la definici&amp;oacute;n del campo. Por otro lado, en el code-behind de la p&amp;aacute;gina, crearemos un manipulador para el evento ContentLoaded; donde comprobaremos si la operaci&amp;oacute;n de edici&amp;oacute;n corresponde a la creaci&amp;oacute;n de una nueva entidad (enumeraci&amp;oacute;n DataFormMode), y en caso afirmativo, obtendremos la entidad actualmente en curso, asignando la fecha del sistema a su propiedad InvoiceDate.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Fecha:&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;IsEnabled&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;sdk:DatePicker&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;dtInvoiceDate&amp;quot;&lt;/span&gt;
                    &lt;span style="color:#ff0000;"&gt;SelectedDate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceDate, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;110&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; frmInvoices_ContentLoaded(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, DataFormContentLoadEventArgs e)
{
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.Mode == DataFormMode.AddNew)
    {
        Invoice oInvoice = (Invoice)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.CurrentItem;
        oInvoice.InvoiceDate = DateTime.Today;
        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;FirstInvoice&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Otro campo que al igual que los dos anteriores no podr&amp;aacute; ser modificado, debiendo tomar el valor true, o lo que es igual, mostrar un CheckBox con la casilla marcada.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Primera factura?:&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;IsEnabled&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;False&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;CheckBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;IsChecked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=FirstInvoice, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; frmInvoices_ContentLoaded(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, DataFormContentLoadEventArgs e)
{
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.Mode == DataFormMode.AddNew)
    {
        Invoice oInvoice = (Invoice)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.CurrentItem;
        &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
        oInvoice.FirstInvoice = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
    }
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;BillingAddress&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;A diferencia de los campos anteriores, la direcci&amp;oacute;n de la factura s&amp;iacute; podr&amp;aacute; ser editada por el usuario. Sin embargo, este campo tendr&amp;aacute; que tomar como valor inicial la cadena &amp;quot;C/&amp;quot;, y adicionalmente, al recibir el foco, tendr&amp;aacute; que posicionarse al final del texto del control; esto &amp;uacute;ltimo lo lograremos codificando el evento GotFocus del control de edici&amp;oacute;n.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Direcci&amp;oacute;n:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;txtBillingAddress&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingAddress, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;150&amp;quot;&lt;/span&gt; 
                &lt;span style="color:#ff0000;"&gt;GotFocus&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;txtBillingAddress_GotFocus&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; txtBillingAddress_GotFocus(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)
{
    ((TextBox)sender).Select(((TextBox)sender).Text.Length, 0);
}
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;&lt;/div&gt;
&lt;p&gt;&lt;b&gt;CustomerId&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;El DataForm asigna de manera predeterminada el valor cero a los campos num&amp;eacute;ricos cuando se trata de nuevas entidades. En el campo CustomerId este comportamiento puede resultar especialmente inc&amp;oacute;modo, ya que en la pr&amp;aacute;ctica totalidad de las ocasiones, el usuario debe borrar el cero y teclear un c&amp;oacute;digo v&amp;aacute;lido de cliente. Por tal causa, en el evento GotFocus de este control de edici&amp;oacute;n a&amp;ntilde;adiremos el c&amp;oacute;digo necesario para que autom&amp;aacute;ticamente sea borrado su contenido si s&amp;oacute;lo hay un cero.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo cliente:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;txtCustomerId&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=CustomerId, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;40&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt; 
                &lt;span style="color:#ff0000;"&gt;GotFocus&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;txtCustomerId_GotFocus&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; txtCustomerId_GotFocus(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; sender, RoutedEventArgs e)
{
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.Mode == DataFormMode.AddNew)
    {
        TextBox txtCustomerId = (TextBox)&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.frmInvoices.FindNameInContent(&lt;span style="color:#006080;"&gt;&amp;quot;txtCustomerId&amp;quot;&lt;/span&gt;);

        &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (txtCustomerId.Text == &lt;span style="color:#006080;"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;)
        {
            txtCustomerId.Text = &lt;span style="color:#0000ff;"&gt;string&lt;/span&gt;.Empty;
        }
    }
}
&lt;/pre&gt;
&amp;nbsp;&lt;/div&gt;
&lt;p&gt;Tras escribir todo este c&amp;oacute;digo declarativo y de comportamiento para la plantilla de inserci&amp;oacute;n, ejecutaremos la aplicaci&amp;oacute;n, que tendr&amp;aacute; el aspecto de la siguiente figura durante la creaci&amp;oacute;n de una nueva entidad.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas2_5F00_17.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;La creaci&amp;oacute;n de nuevos valores utilizando la plantilla NewItemTemplate pone punto final a este art&amp;iacute;culo, en el que nos hemos aproximado a las operaciones de edici&amp;oacute;n que desde el control DataForm de Silverlight pueden realizarse a trav&amp;eacute;s de las plantillas que este control proporciona. Confiamos en que os resulte de utilidad.&lt;/p&gt;
&lt;p&gt;Un saludo.&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://geeks.ms/aggbug.aspx?PostID=183350" width="1" height="1"&gt;</content><author><name>lmblanco</name><uri>http://geeks.ms/members/lmblanco/default.aspx</uri></author><category term="Silverlight" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/Silverlight/default.aspx" /><category term="WCF RIA Services" scheme="http://geeks.ms/blogs/lmblanco/archive/tags/WCF+RIA+Services/default.aspx" /></entry><entry><title>DataForm EditTemplate y NewItemTemplate. Edición de datos en Silverlight mediante plantillas (1)</title><link rel="alternate" type="text/html" href="/blogs/lmblanco/archive/2010/10/13/dataform-edittemplate-y-newitemtemplate-edici-243-n-de-datos-en-silverlight-mediante-plantillas-1.aspx" /><id>/blogs/lmblanco/archive/2010/10/13/dataform-edittemplate-y-newitemtemplate-edici-243-n-de-datos-en-silverlight-mediante-plantillas-1.aspx</id><published>2010-10-13T18:38:00Z</published><updated>2010-10-13T18:38:00Z</updated><content type="html">&lt;p&gt;Continuando con la t&amp;oacute;nica iniciada en el &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2010/08/26/plantillas-de-presentaci-243-n-de-datos-en-el-control-dataform-de-silverlight-1.aspx"&gt;art&amp;iacute;culo&lt;/a&gt; sobre la plantilla ReadOnlyTemplate del control DataForm, en esta ocasi&amp;oacute;n abordaremos el desarrollo de un formulario centr&amp;aacute;ndonos en los aspectos relativos a la edici&amp;oacute;n de datos, utilizando las plantillas que a tal efecto este control proporciona.&lt;/p&gt;
&lt;p&gt;En esta primera entrega crearemos el proyecto de ejemplo sobre el que trabajaremos, realizando una introducci&amp;oacute;n al uso de la plantilla EditTemplate, donde explicaremos el comportamiento predeterminado que muestra durante la edici&amp;oacute;n de los datos. En la segunda parte abordaremos la posibilidad de otorgar al usuario un mayor control sobre la operaci&amp;oacute;n de edici&amp;oacute;n, as&amp;iacute; como el borrado de datos. Tambi&amp;eacute;n nos ocuparemos de la inserci&amp;oacute;n de nuevos valores empleando la plantilla NewItemTemplate.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;La fuente de datos&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;En el presente art&amp;iacute;culo volveremos a usar la base de datos MusicaGest, cuya tabla Invoice est&amp;aacute; basada en la tabla del mismo nombre de la base de datos Chinook, disponible en CodePlex. Podemos ver el script de creaci&amp;oacute;n en el art&amp;iacute;culo sobre la plantilla ReadOnlyTemplate anteriormente mencionado.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;El proyecto de ejemplo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Antes de empezar a trabajar en el dise&amp;ntilde;o de la plantilla crearemos en Visual Studio 2010 el proyecto de ejemplo (de tipo Silverlight Application con WCF RIA Services habilitado) que nos acompa&amp;ntilde;ar&amp;aacute; a lo largo del art&amp;iacute;culo, al que daremos el nombre de PlantillasEdicion, y cuyo c&amp;oacute;digo fuente podemos encontrar &lt;a href="http://geeks.ms/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.EjemplosArticulos.201010/PlantillasEdicionZip.txt"&gt;aqu&amp;iacute;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Obtendremos como resultado una soluci&amp;oacute;n compuesta por dos proyectos: uno de ellos ser&amp;aacute; un proyecto Web que representa a la parte servidora de la aplicaci&amp;oacute;n, y el otro un proyecto Silverlight que representa a la parte cliente.&lt;/p&gt;
&lt;p&gt;Como elementos de partida de la aplicaci&amp;oacute;n, en el proyecto Web crearemos un modelo de datos conectado a la base de datos MusicaGest, y un servicio de dominio para manejar la entidad Invoice proporcionada por el modelo de datos.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas1_5F00_01.jpg" border="0" style="max-width:550px;" alt="" /&gt;&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; MusicaGestDomainService : LinqToEntitiesDomainService&amp;lt;MusicaGestEntities&amp;gt;
{
    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IQueryable&amp;lt;Invoice&amp;gt; GetInvoices()
    {
        &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.ObjectContext.Invoices;
    }
    &lt;span style="color:#008000;"&gt;//....&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Comportamiento predeterminado en edici&amp;oacute;n&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;A continuaci&amp;oacute;n abriremos la p&amp;aacute;gina MainPage.xaml, a&amp;ntilde;adiendo un DomainDataSource y un DataForm, en los que estableceremos la configuraci&amp;oacute;n m&amp;iacute;nima que permita su funcionamiento.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Class&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;PlantillaEdicion.MainPage&amp;quot;&lt;/span&gt;    
&lt;span style="color:#ff0000;"&gt;xmlns:riaControls&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.DomainServices&amp;quot;&lt;/span&gt;
&lt;span style="color:#ff0000;"&gt;xmlns:domainctx&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;clr-namespace:PlantillaEdicion.Web&amp;quot;&lt;/span&gt;    &lt;span style="color:#ff0000;"&gt;xmlns:toolkit&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit&amp;quot;&lt;/span&gt;  
    &amp;lt;&lt;span style="color:#ff0000;"&gt;--&lt;/span&gt;....&lt;span style="color:#ff0000;"&gt;--&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;ddsInvoices&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;QueryName&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;GetInvoices&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.DomainContext&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;domainctx:MusicaGestDomainContext&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource.DomainContext&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;riaControls:DomainDataSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;ItemsSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding ElementName=ddsInvoices, Path=Data}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Margin&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;5&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;El DataForm generar&amp;aacute; un control de edici&amp;oacute;n (campo) por cada propiedad de la entidad a la que se encuentra enlazada a trav&amp;eacute;s del DomainDataSource. Para los valores textuales y num&amp;eacute;ricos se utilizar&amp;aacute;n controles TextBox, para las fechas DatePicker, y para los l&amp;oacute;gicos CheckBox.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas1_5F00_02.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Esta sencillez en la creaci&amp;oacute;n del formulario de datos arroja algunos inconvenientes, entre los que destacar&amp;iacute;amos el hecho de que el nombre de los campos de la tabla se usa para ordenar los campos del DataForm, aunque rara vez el orden de los campos resulta adecuado de esta manera. El nombre del campo tambi&amp;eacute;n se emplea como t&amp;iacute;tulo situado al lado de cada control de edici&amp;oacute;n, lo que puede resultar poco descriptivo en ocasiones. Respecto a las dimensiones de los campos, encontramos que todos mantienen la misma anchura, siendo esto algo innecesario en campos como CustomerId, InvoiceDate o Total, por poner un ejemplo.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;La plantilla EditTemplate&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Si bien podr&amp;iacute;amos solucionar parte de los problemas que acabamos de plantear aplicando ciertos atributos del espacio de nombres DataAnnotations a los metadatos de la entidad Invoice, tal y como se explica &lt;a href="http://geeks.ms/blogs/lmblanco/archive/2010/06/20/validaci-243-n-en-acci-243-n-con-el-control-dataform-de-silverlight-1.aspx"&gt;aqu&amp;iacute;&lt;/a&gt;, en esta ocasi&amp;oacute;n vamos a recurrir a la plantilla EditTemplate, que utilizaremos para aquellas operaciones de modificaci&amp;oacute;n de los valores existentes en la colecci&amp;oacute;n de entidades enlazadas al formulario de datos. Mediante esta plantilla podremos conseguir una interfaz de usuario mucho m&amp;aacute;s flexible y personalizable que la generada por el DataForm autom&amp;aacute;ticamente. &lt;/p&gt;
&lt;p&gt;Volviendo al editor de c&amp;oacute;digo de la p&amp;aacute;gina MainPage.xaml, dentro de la declaraci&amp;oacute;n del DataForm situaremos la plantilla utilizando las etiquetas EditTemplate y DataTemplate.&amp;nbsp;&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;ItemsSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding ElementName=ddsInvoices, Path=Data}&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;Margin&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;5&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.EditTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.EditTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Como acabamos de comprobar en el anterior bloque de c&amp;oacute;digo, tambi&amp;eacute;n incluiremos un elemento contenedor dentro de DataTemplate (un panel StackPanel), ya que de no hacerlo as&amp;iacute;, se producir&amp;iacute;a un error que indicar&amp;iacute;a que la propiedad VisualTree est&amp;aacute; asignada m&amp;aacute;s de una vez.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas1_5F00_03.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;A partir de aqu&amp;iacute;, para cada campo que queramos a&amp;ntilde;adir al DataForm agregaremos una etiqueta DataField (igual que en la plantilla ReadOnlyTemplate), en cuyo interior situaremos el control con el que editaremos el valor del campo, o bien, un control de s&amp;oacute;lo lectura en caso de que el campo no deba ser modificado. Por otro lado, tambi&amp;eacute;n deberemos asignar a la propiedad del control encargada de visualizar el valor del campo una expresi&amp;oacute;n de enlace a datos, que obtenga dicho valor y lo presente en el control.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl.Resources&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Style&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;TargetType&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;TextBox&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;Setter&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Property&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;HorizontalAlignment&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Value&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;Style&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;UserControl.Resources&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;span style="color:#008000;"&gt;&amp;lt;!--....--&amp;gt;&lt;/span&gt;

&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;x:Name&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;frmInvoices&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;ItemsSource&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding ElementName=ddsInvoices, Path=Data}&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;Margin&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;5&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.EditTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo factura:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceId, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;40&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo cliente:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=CustomerId, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;40&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Fecha:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;sdk:DatePicker&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;SelectedDate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceDate, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                                    &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;110&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;HorizontalAlignment&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Left&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Direcci&amp;oacute;n:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingAddress, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;150&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Ciudad:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingCity, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;120&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Pa&amp;iacute;s:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=BillingCountry, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;80&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Importe:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=Total, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;50&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

                &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Primera factura?:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;CheckBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;IsChecked&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=FirstInvoice, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
            &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;StackPanel&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;DataTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataForm.EditTemplate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Gracias al uso de la plantilla EditTemplate podemos resolver el conjunto de inconvenientes mencionados en el apartado anterior. En primer lugar, el orden de los campos viene determinado por la posici&amp;oacute;n con la que situemos las etiquetas DataField dentro de la plantilla y no por su nombre; para los t&amp;iacute;tulos de los campos empleamos la propiedad Label del DataField; y para ajustar su tama&amp;ntilde;o, en el control de edici&amp;oacute;n usamos la propiedad Width combinada con HorizontalAlignment, &amp;eacute;sta &amp;uacute;ltima establecida como recurso para controles de tipo TextBox, que son la mayor&amp;iacute;a de los que componen el formulario.&lt;/p&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas1_5F00_04.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Los controles de edici&amp;oacute;n que estamos utilizando para los campos de la plantilla son iguales a los que emplea el DataForm cuando los genera autom&amp;aacute;ticamente. Sin embargo, si hacemos una r&amp;aacute;pida revisi&amp;oacute;n de los controles disponibles en la Barra de Herramientas de Visual Studio, podremos deducir que para los valores que deben manejar ciertos campos, el usuario obtendr&amp;iacute;a una experiencia m&amp;aacute;s satisfactoria usando otro tipo de controles m&amp;aacute;s especializados. Este es un tema que tiene la suficiente entidad y amplitud para tratarse por separado, por lo que ser&amp;aacute; abordado en pr&amp;oacute;ximos art&amp;iacute;culos.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Campos no editables&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Puesto que el campo InvoiceId tiene activado el atributo Identity en la tabla de la base de datos, su valor es generado por el motor de datos y no debe ser modificado. El control DataForm es consciente de este tipo de situaciones, y por ello, el control TextBox que estamos empleando como campo del formulario no permite ser editado. Este comportamiento se produce porque, internamente, el DataForm est&amp;aacute; asignando el valor True a la propiedad IsReadOnly del DataField asociado al campo InvoiceId.&lt;/p&gt;
&lt;p&gt;Tambi&amp;eacute;n podemos, naturalmente, asignar de forma manual esta propiedad a cualquier otro campo del formulario que necesitemos. A continuaci&amp;oacute;n lo vemos aplicado sobre el campo CustomerId.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo cliente:&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;IsReadOnly&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;True&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=CustomerId, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&lt;img src="http://geeks.ms/cfs-filesystemfile.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/lmblanco.ImagenesArticulos.201010/DataFormEditTemplateNewItemTemplateEdicionDatosSilverlighMediantePlantillas1_5F00_05.jpg" border="0" style="max-width:550px;" alt="" /&gt;&amp;nbsp;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Una v&amp;iacute;a alternativa, que ser&amp;aacute; la que utilicemos en el proyecto de ejemplo de este art&amp;iacute;culo, consiste en emplear un control no editable (TextBlock, Label, etc.) para aquellos campos que no deban ser modificados. En nuestro caso emplearemos un TextBlock para el campo InvoiceId, volviendo a dejar editable el campo CustomerId.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo factura:&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBlock&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceId, Mode=OneWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Descripci&amp;oacute;n extendida de campo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;La posibilidad de que los campos del DataForm dispongan de un texto adicional, explicativo de su contenido, es una caracter&amp;iacute;stica que podemos lograr a trav&amp;eacute;s de la propiedad Description de la etiqueta DataField.&lt;/p&gt;
&lt;div&gt;
&lt;pre style="line-height:12pt;background-color:#f4f4f4;margin:0em;width:100%;font-family:Consolas, &amp;#39;Courier New&amp;#39;, Courier, Monospace;color:black;font-size:10pt;overflow:visible;border-style:none;padding:0px;"&gt;&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo factura:&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;N&amp;uacute;mero de factura&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceId, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;40&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;C&amp;oacute;digo cliente:&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Identificador del cliente&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;TextBox&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Text&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=CustomerId, Mode=TwoWay}&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;40&amp;quot;&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;/&amp;gt;&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;&amp;lt;/&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;

&lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;toolkit:DataField&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Label&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Fecha:&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Description&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;Fecha de emisi&amp;oacute;n de la factura&amp;quot;&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;&amp;gt;&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;&amp;lt;&lt;/span&gt;&lt;span style="color:#800000;"&gt;sdk:DatePicker&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;SelectedDate&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;{Binding Path=InvoiceDate, Mode=TwoWay}&amp;quot;&lt;/span&gt; 
                    &lt;span style="color:#ff0000;"&gt;Width&lt;/span&gt;&lt;span style="color:#0000ff;"&gt;=&amp;quot;110&amp;quot;&lt;/span&gt; &lt;span style="color:#ff0000;"&gt;Horiz
