<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Quemando cromo &#187; Visual Basic 2008</title>
	<atom:link href="http://cromo.cda-ie.es/category/programacion/visual-basic-2008/feed/" rel="self" type="application/rss+xml" />
	<link>http://cromo.cda-ie.es</link>
	<description>Hacía calor, la noche que quemamos a Cromo</description>
	<lastBuildDate>Tue, 27 Dec 2011 08:07:53 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>El problema de la barra de progreso</title>
		<link>http://cromo.cda-ie.es/2011/12/27/el-problema-de-la-barra-de-progreso/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=el-problema-de-la-barra-de-progreso</link>
		<comments>http://cromo.cda-ie.es/2011/12/27/el-problema-de-la-barra-de-progreso/#comments</comments>
		<pubDate>Tue, 27 Dec 2011 08:07:53 +0000</pubDate>
		<dc:creator>Cubano</dc:creator>
				<category><![CDATA[Visual Basic 2005]]></category>
		<category><![CDATA[Visual Basic 2008]]></category>
		<category><![CDATA[Visual Basic 2010]]></category>

		<guid isPermaLink="false">http://cromo.cda-ie.es/?p=382</guid>
		<description><![CDATA[El año pasado, intentando desembarazarme de una tarea tediosa que dejaba frito mi equipo, usé mi primera función recursiva con utilidad práctica. Como la tarea consumía su tiempo, tiré de un BackGroundWorker. Componente sencillo de usar y con ejemplos bastante claros en la ayuda de Visual Studio. No problem: tenía un valor de entrada pedido [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">El año pasado, intentando desembarazarme de una tarea tediosa que dejaba frito mi equipo, usé mi primera función recursiva con utilidad práctica. Como la tarea consumía su tiempo, tiré de un </span><span style="font-family:Courier New"><strong>BackGroundWorker</strong></span><span style="font-family:Verdana">. Componente sencillo de usar y con ejemplos bastante claros en la ayuda de Visual Studio. No problem: tenía un valor de entrada pedido por el usuario, se realizaban n operaciones de forma recursiva, se obtenía un valor de salida.<br />
</span></span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Como el proceso era algo largo (mínimo unos diez segundos, pero podía llegar superar el minuto en la versión 2, que admitía de entrada una serie de valores), se me ocurrió usar una barra de progreso para mantener informado al usuario.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Entonces empezaron los problemas.<br />
</span></p>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Todos los ejemplos que he visto que usan el evento </span><span style="font-family:Courier New"><strong>ProgressChanged</strong></span><span style="font-family:Verdana"> del </span><span style="font-family:Courier New"><strong>BackGroundWorker</strong></span><span style="font-family:Verdana"> para alimentar una barra de progreso presentan una serie de operaciones en secuencia con llamadas a </span><span style="font-family:Courier New"><strong>ProgressChanged</strong></span><span style="font-family:Verdana"> entre ellas, es decir: hago paso 1; progreso cambiado; hago paso 2; progreso cambiado… Sin embargo, mi problema era otro: tengo una instancia de mi clase de trabajo, cojo los valores del usuario (a través de </span><span style="font-family:Courier New"><strong>DoWorkEventArgs.Argument</strong></span><span style="font-family:Verdana">), se los paso, y le digo &#8220;ea, majo. Tú puedes&#8221; llamando al método </span><span style="font-family:Courier New"><strong>MiClase.HacerCurro</strong></span><span style="font-family:Verdana">. Ahí dentro se harán las n operaciones (recursivas), número desconocido hasta que se hagan.<br />
</span></span></p>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Vale, pensé. Puedo provocar un evento </span><span style="font-family:Courier New"><strong>OperaciónCompletada</strong></span><span style="font-family:Verdana"> cada vez que complete una operación. Pero la instancia de </span><span style="font-family:Courier New"><strong>MiClase</strong></span><span style="font-family:Verdana"> está declarada dentro del </span><span style="font-family:Courier New"><strong>DoWork</strong></span><span style="font-family:Verdana"> del </span><span style="font-family:Courier New"><strong>BackGroundWorker</strong></span><span style="font-family:Verdana">. No tengo acceso desde fuera. ¿Cómo lo hago?<br />
</span></span></p>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">¿Y si meto alguien que escuche en el </span><span style="font-family:Courier New"><strong>DoWork</strong></span><span style="font-family:Verdana">? De esta forma tendría mi &#8220;escuchador&#8221; de eventos en el mismo hilo. Es decir, una clase, digamos </span><span style="font-family:Courier New"><strong>Escuchante</strong></span><span style="font-family:Verdana">, a la que le paso mi instancia de </span><span style="font-family:Courier New"><strong>MiClase</strong></span><span style="font-family:Verdana"> y la del </span><span style="font-family:Courier New"><strong>BackGroundWorker</strong></span><span style="font-family:Verdana">. Escuchante gestiona el evento </span><span style="font-family:Courier New"><strong>OperacionCompletada</strong></span><span style="font-family:Verdana"> provocando a su vez el </span><span style="font-family:Courier New"><strong>ProgressChanged</strong></span><span style="font-family:Verdana">, que actualiza la barra de progreso.<br />
</span></span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">No sé si será una solución muy limpia, pero funcionó.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">En resumen, algo así:<br />
</span></p>
<p ><span style="font-family:Courier New; font-size:10pt">Public Class Escuchante<br />
</span></p>
<p ><span style="font-family:Courier New; font-size:10pt">Private WithEvents _MiClase as MiClase<br />
</span></p>
<p ><span style="font-family:Courier New; font-size:10pt">Private _MiBGW as BackGroundWorker<br />
</span></p>
<p ><span style="font-family:Courier New; font-size:10pt">Public Sub New(mc as MiClase, bw as BackGroundWorker)<br />
</span></p>
<p style="margin-left: 36pt"><span style="font-family:Courier New; font-size:10pt">_MiClase=mc<br />
</span></p>
<p style="margin-left: 36pt"><span style="font-family:Courier New; font-size:10pt">_MiBGW=bw<br />
</span></p>
<p ><span style="font-family:Courier New; font-size:10pt">End Sub<br />
</span></p>
<p ><span style="font-family:Courier New; font-size:10pt">Private Sub OpCompletada(sender as Object, e as OperacionCompletadaEventArgs) _<br />
</span></p>
<p ><span style="font-family:Courier New; font-size:10pt">                                    Handles _MiClase.OperacionCompletada<br />
</span></p>
<p style="margin-left: 36pt"><span style="font-family:Courier New; font-size:10pt">_MiBGW.ReportProgress=e.NumOp<br />
</span></p>
<p ><span style="font-family:Courier New; font-size:10pt">End Sub<br />
</span></p>
<p ><span style="font-family:Courier New; font-size:10pt">End Class</span></p>
]]></content:encoded>
			<wfw:commentRss>http://cromo.cda-ie.es/2011/12/27/el-problema-de-la-barra-de-progreso/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Pegar datos de una hoja de Excel a un DataGridView</title>
		<link>http://cromo.cda-ie.es/2011/01/18/pegar-datos-de-una-hoja-de-excel-a-un-datagridview/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=pegar-datos-de-una-hoja-de-excel-a-un-datagridview</link>
		<comments>http://cromo.cda-ie.es/2011/01/18/pegar-datos-de-una-hoja-de-excel-a-un-datagridview/#comments</comments>
		<pubDate>Tue, 18 Jan 2011 21:05:29 +0000</pubDate>
		<dc:creator>Cubano</dc:creator>
				<category><![CDATA[Visual Basic 2005]]></category>
		<category><![CDATA[Visual Basic 2008]]></category>
		<category><![CDATA[Visual Basic 2010]]></category>

		<guid isPermaLink="false">http://cromo.cda-ie.es/?p=338</guid>
		<description><![CDATA[Un intento de simplificar el uso de una aplicación por lo demás bastante simple (de cara al usuario) me ha llevado a jugar con el portapapeles para permitir que el usuario copie una serie de valores de una hoja de cálculo (Excel, para más señas) y las pegue en un DataGridView, algo que me ha [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Un intento de simplificar el uso de una aplicación por lo demás bastante simple (de cara al usuario) me ha llevado a jugar con el portapapeles para permitir que el usuario copie una serie de valores de una hoja de cálculo (Excel, para más señas) y las pegue en un DataGridView, algo que me ha costado un buen rato, no porque sea complicado, sino porque no he encontrado información al respecto por Internet (seguramente por la torpeza &#8220;buscativa&#8221; de uno).</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">El problema, como digo, no es complicado. Por una parte, acceder al portapapeles es muy sencillo, mediante My.Computer.Clipboard y hay varios métodos para extraer su contenido según lo que contenga. En este caso (la copia de texto) usaremos el método GetText, que nos devuelve un String. El dónde gestionar esto ya queda a gusto del consumidor pero, para mí, lo más fácil es añadir un menú contextual con el habitual atajo de teclado (Ctrl + V).</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">El siguiente paso es tratar ese texto. Cualquier colección de celdas de Excel es copiada al portapapeles como un conjunto de valores separados por tabulación. El otro día mostraba el uso de la clase <b><a href="http://cromo.cda-ie.es/2010/11/23/leer-ficheros-csv-y-de-campos-de-ancho-fijo-en-visual-basic/">TextFieldParser</a></b> para procesar ficheros de texto que nos viene como anillo al dedo. Bueno, casi, porque al TextFieldParser no le podemos pasar un String, está pensado para procesar ficheros. Si vemos sus constructores, a uno se le pasa la ruta de un fichero, a otro un Stream, precisamente para tratar con un fichero, y a la tercera sobrecarga, un TextReader.</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">¿Qué es un TextReader (era la primera vez que lo veía)? Según la biblioteca de MSDN, TextReader es la clase abstracta de StreamReader (éste si lo conocía) y StringReader. Éste último tiene en su nombre la palabra mágica, String, así que merece la pena echar un ojo. Me da igual los tutoriales que nos puedan aparecer ni los mil usos que tenga StringReader. Para el caso que nos ocupa, todo se reduce a crear un StringReader a partir del texto contenido en el portapapeles:</span></p>
<p><span style="font-family:Courier New; font-size:10pt"><span style="color:blue">Dim</span> miTexto <span style="color:blue">As</span> <span style="color:#2b91af">StringReader</span></span></p>
<p><span style="font-family:Courier New; font-size:10pt">miTexto = <span style="color:blue">New</span> <span style="color:#2b91af">StringReader</span>(<span style="color:blue">My</span>.Computer.Clipboard.GetText)</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Y pasarle ese StringReader a un TextFieldParser, con lo que estamos casi, casi, en el mismo caso del ejemplo de TextFieldParser. Ya podemos trabajar de forma simple con el texto del portapapeles. Sólo hay que añadir los controles de errores necesarios y decidir qué vamos a hacer con cada fila válida devuelta por el TextFieldParser. Siguiendo la lógica del título de esta entrada, pasárselas al DataGridView, pero tengo que confesar que no lo hice así. La razón es muy simple: me interesaba más pasárselo directamente al origen de datos del DataGridView.</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Para mi caso concreto (Origen de datos + BindingSource + DataGridView), antes de iniciar el proceso de lectura de TextFieldParser, llamé al CancelEdit del BindingSource para evitar la posibilidad de que se generase una fila en blanco o no válida (si se da el caso, se saltaría la validación de datos) y le quité también la referencia al DataSource:</span></p>
<p style="text-align: justify"><span style="font-family:Courier New; font-size:10pt"><span style="color:blue">Me</span>.bsArticulos.CancelEdit()<br />
</span></p>
<p><span style="font-family:Courier New; font-size:10pt"><span style="color:blue">Me</span>.bsArticulos.DataSource = <span style="color:#a31515">&#8220;&#8221;<br />
</span></span></p>
<p><span style="font-family:Verdana; font-size:10pt">Después de añadir los valores del portapapeles al origen de datos, se vuelve a enlazar el BindingSource con éste y listo. Bueno, vale, no he pegado realmente en el DataGridView. Espero que nadie se sienta estafado.<br />
</span></p>
<p><span style="font-family:Verdana; font-size:10pt">Nos vemos en el <em>Forlon.</em></span></p>
]]></content:encoded>
			<wfw:commentRss>http://cromo.cda-ie.es/2011/01/18/pegar-datos-de-una-hoja-de-excel-a-un-datagridview/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Leer ficheros csv y de campos de ancho fijo en Visual Basic</title>
		<link>http://cromo.cda-ie.es/2010/11/23/leer-ficheros-csv-y-de-campos-de-ancho-fijo-en-visual-basic/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=leer-ficheros-csv-y-de-campos-de-ancho-fijo-en-visual-basic</link>
		<comments>http://cromo.cda-ie.es/2010/11/23/leer-ficheros-csv-y-de-campos-de-ancho-fijo-en-visual-basic/#comments</comments>
		<pubDate>Tue, 23 Nov 2010 14:21:10 +0000</pubDate>
		<dc:creator>Cubano</dc:creator>
				<category><![CDATA[Visual Basic 2005]]></category>
		<category><![CDATA[Visual Basic 2008]]></category>

		<guid isPermaLink="false">http://cromo.cda-ie.es/?p=323</guid>
		<description><![CDATA[En mi vuelta al servicio activo he tenido que procesar dos ficheros en texto plano: uno con campos separados por un carácter y otro con campos de ancho fijo. En su día ya lo hice (concretamente para un csv, valores separados por comas), pero no me acordaba de cómo lo hice (fue al poco de [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">En mi vuelta al servicio activo he tenido que procesar dos ficheros en texto plano: uno con campos separados por un carácter y otro con campos de ancho fijo. En su día ya lo hice (concretamente para un csv, valores separados por comas), pero no me acordaba de cómo lo hice (fue al poco de empezar con VB2005) y no tenía a mano ni el código que hice ni el libro que usé de referencia, así que busqué en Internet.<br />
</span></p>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Y fíjese usted por donde, encontré una forma más simple de hacer las cosas que no conocía: usando la clase </span><a href="http://msdn.microsoft.com/es-es/library/ms128079.aspx"/><span style="font-family:Courier New">TextFieldParser</span></a><span style="font-family:Verdana">.</span></p>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">En la forma más fácil, le pasamos en el constructor la ruta del archivo a tratar. Le indicamos luego qué es, si de ancho fijo (</span><span style="font-family:Courier New"><strong>FixedWith</strong></span><span style="font-family:Verdana">) o separado por carácter (</span><span style="font-family:Courier New"><strong>Delimited</strong></span><span style="font-family:Verdana">) con la propiedad </span><span style="font-family:Courier New"><strong>TextFieldType</strong></span><span style="font-family:Verdana">. Si es el segundo caso, con el método </span><span style="font-family:Courier New"><strong>SetDelimiters</strong></span><span style="font-family:Verdana"> indicamos el delimitador (por ejemplo, </span><span style="font-family:Courier New">MiTfp.SetDelimiters(vbTab)</span><span style="font-family:Verdana"> para indicar campos separados por una tabulación).</span></p>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">En el primero, indicaríamos el ancho de los campos mediante una lista de enteros que le pasamos al método </span><span style="font-family:Courier New"><strong>SetFieldWiths</strong></span><span style="font-family:Verdana">: </span><span style="font-family:Courier New">MiTfp.SetFieldWiths(2, 3, 12, 85, 5)</span><span style="font-family:Verdana">.</span></p>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Para leer cada línea tenemos el método </span><span style="font-family:Courier New"><strong>ReadFields</strong></span><span style="font-family:Verdana">, que nos devuelve un array de cadenas con cada campo de la línea del fichero en la posición correspondiente del array. Se tarda más en explicar que en hacer.</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Hay un pequeño problema adicional: la codificación de caracteres. Por defecto, se usa UTF8. Ahora mismo no recuerdo si Vista y 7 usan UTF8 por defecto, pero XP y versiones anteriores de Windows, no, y podemos encontrarnos con problemas con algunos caracteres, como ñ, tildes, etc. En ese caso, seguramente estemos usando Windows occidental (Windows 1252) o, más raramente, ISO-8859-1. Podemos indicarle esto al TextFieldParser en el constructor, pasándole el código de <a href="http://msdn.microsoft.com/es-es/library/system.text.encoding%28v=VS.100%29.aspx">la página de códigos</a> a emplear:</span></p>
<p style="text-align: justify"><span style="font-family:Courier New; font-size:10pt">Dim MiTfp as New TextFieldParser(MiRuta, System.Text.Encoding.GetEncoding(1252))<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Lo más largo, como siempre, es el control de errores, o el propio tratamiento de los valores que hayamos leído, pero el hecho de leer en sí más simple no puede ser.<br />
</span></p>
]]></content:encoded>
			<wfw:commentRss>http://cromo.cda-ie.es/2010/11/23/leer-ficheros-csv-y-de-campos-de-ancho-fijo-en-visual-basic/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DataRepeater y el evento Enter de sus controles</title>
		<link>http://cromo.cda-ie.es/2010/11/16/datarepeater-y-el-evento-enter-de-sus-controles/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=datarepeater-y-el-evento-enter-de-sus-controles</link>
		<comments>http://cromo.cda-ie.es/2010/11/16/datarepeater-y-el-evento-enter-de-sus-controles/#comments</comments>
		<pubDate>Tue, 16 Nov 2010 10:24:18 +0000</pubDate>
		<dc:creator>Cubano</dc:creator>
				<category><![CDATA[Visual Basic 2005]]></category>
		<category><![CDATA[Visual Basic 2008]]></category>

		<guid isPermaLink="false">http://cromo.cda-ie.es/2010/11/12/datarepeater-y-el-evento-enter-de-sus-controles/</guid>
		<description><![CDATA[A la hora de evitar que el usuario manazas edite el valor de algún control, una opción habitual es controlar el evento Enter de ese control o de su contenedor (un GroupBox, un Panel&#8230;), mandando el foco a otro control mediante el método OtroControl.Select(). Esto funciona para buena parte de los controles disponibles en Windows [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-family:Verdana; font-size:10pt">A la hora de evitar que el usuario manazas edite el valor de algún control, una opción habitual es controlar el evento Enter de ese control o de su contenedor (un GroupBox, un Panel&#8230;), mandando el foco a otro control mediante el método OtroControl.Select(). Esto funciona para buena parte de los controles disponibles en Windows Forms, pero no para todos (dtpicker, optionbutton&#8230; hay varios que pasarán de nosotros).<br />
</span></p>
<p><span style="font-family:Verdana; font-size:10pt">Si nosotros queremos usar este sistema con controles que estén dentro de un DataRepeater&#8230; En fin, probadlo si queréis, pero ya os digo que la aplicación se quedará muerta si mandáis el foco a un control que esté fuera del DataRepeater. ¿Entonces?<br />
</span></p>
<p><span style="font-family:Verdana; font-size:10pt">Pues no salgamos. Pasemos el foco al ítem del DataRepeater al que pertenezca el control y listo:<br />
</span></p>
<p><span style="font-family:Courier New; font-size:10pt"><strong>MiDataRepeater.CurrentItem.Select()<br />
</strong></span></p>
<p><span style="font-family:Verdana; font-size:10pt">El control DataRepeater es más versátil que el habitual DataGridView, pero es caprichoso como él solo.<br />
</span></p>
]]></content:encoded>
			<wfw:commentRss>http://cromo.cda-ie.es/2010/11/16/datarepeater-y-el-evento-enter-de-sus-controles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Evitar error en consultas de agregado de LINQ</title>
		<link>http://cromo.cda-ie.es/2010/10/28/evitar-error-en-consultas-de-agregado-de-linq/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=evitar-error-en-consultas-de-agregado-de-linq</link>
		<comments>http://cromo.cda-ie.es/2010/10/28/evitar-error-en-consultas-de-agregado-de-linq/#comments</comments>
		<pubDate>Thu, 28 Oct 2010 20:11:53 +0000</pubDate>
		<dc:creator>Cubano</dc:creator>
				<category><![CDATA[Visual Basic 2008]]></category>

		<guid isPermaLink="false">http://cromo.cda-ie.es/2010/10/28/evitar-error-en-consultas-de-agregado-de-linq/</guid>
		<description><![CDATA[Nombre pomposo de la entrada pero que contesta a un problema que se me ha presentado esta mañana (volver a trabajar tiene estas cosas): al calcular el valor máximo de un campo en un conjunto de datos con una consulta LINQ sobre un dataset (por ejemplo, el importe más alto de un determinado cliente) se [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Nombre pomposo de la entrada pero que contesta a un problema que se me ha presentado esta mañana (volver a trabajar tiene estas cosas): al calcular el valor máximo de un campo en un conjunto de datos con una consulta LINQ sobre un dataset (por ejemplo, el importe más alto de un determinado cliente) se producía una excepción si no se devuelve ningún valor (en el ejemplo, si ese cliente no tiene pedidos). Una búsqueda por Internet me ha apuntado como solución usar extensiones de métodos, algo que no domino y se me antojaba excesivamente complicado para la tarea.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Tras pensarlo un poco, he probado a convertir el valor del campo pasado a la instrucción MAX a un tipo Nullable, que acepta valores nulos. En mi caso, como era valores enteros, esa parte de la consulta LINQ quedaría tal que así:<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Courier New; font-size:10pt">Into Max(Ctype(Fila.Campo, Integer?))<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">La consulta ya no da error, y sólo nos queda controlar si hay valor devuelto (propiedad HasValue), convertirlo al tipo que queramos (Integer, en el ejemplo) y seguir adelante. Más sencillo se me hace que otras ideas que he visto por ahí, y más rápido.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Como siempre, si a alguien le resulta de utilidad, pues mejor.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://cromo.cda-ie.es/2010/10/28/evitar-error-en-consultas-de-agregado-de-linq/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Jugando con colecciones Dictionary</title>
		<link>http://cromo.cda-ie.es/2009/12/24/jugando-con-colecciones-dictionary/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=jugando-con-colecciones-dictionary</link>
		<comments>http://cromo.cda-ie.es/2009/12/24/jugando-con-colecciones-dictionary/#comments</comments>
		<pubDate>Thu, 24 Dec 2009 14:23:01 +0000</pubDate>
		<dc:creator>Cubano</dc:creator>
				<category><![CDATA[Visual Basic 2008]]></category>

		<guid isPermaLink="false">http://cromo.cda-ie.es/?p=249</guid>
		<description><![CDATA[Esta entrada podría valer como la tercera de la serie &#8220;Mantener actualizados unos ComboBox&#8221;, pero va en modo corto, que es nochebuena y me dan ganas de hacer algo más acorde con la fecha (ver La tumba de las luciérnagas, por ejemplo). Hagamos un breve resumen: tenemos un formulario maestro-detalle de series y las releases [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify"><span style="font-family: Verdana; font-size: 10pt">Esta entrada podría valer como la tercera de la serie &#8220;Mantener actualizados unos ComboBox&#8221;, pero va en modo corto, que es nochebuena y me dan ganas de hacer algo más acorde con la fecha (ver <em>La tumba de las luciérnagas</em>, por ejemplo). Hagamos un breve resumen: tenemos un formulario maestro-detalle de series y las <em>releases</em> o distintas versiones de esas series. Como el número de <em>releases</em> por serie es pequeño (0 a 3 ó 4) y el número de campos de la tabla <em>releases</em> es amplio, en lugar de usar una rejilla o algún control parecido, decidí emplear un TabControl que mostrara tantas pestañas como <em>releases</em> y, en cada una, un UserControl con todos los datos. Es decir, esto:</span> </p>
<p style="text-align: center;"><img style="border: 0pt none; margin: 5px;" src="http://i114.photobucket.com/albums/n280/ercubano/Foro/pestagnarelease.jpg" alt="" width="400" height="200" /></p>
<p><span id="more-249"></span></p>
<p style="text-align: justify"><span style="font-family: Verdana; font-size: 10pt">Cada ComboBox del UserControl muestra el contenido de otra tabla (sí, son unas cuantas). Podría haber dejado los combos sólo para altas y modificaciones y haber usado una consulta más específica en lugar de traerme la tabla <em>releases</em> a capón, pero aquí no me gustó la idea (en otra aplicación con un problema parecido es lo que hice; claro, que también usaba SQL Server y pude crear una vista). En lugar de eso, aprovechando que todas esas tablas tienen (y tendrán) un pequeño número de registros (menos de veinte), decidí cargar todos esos datos en memoria. Bueno, no todos, sólo la clave primaria y el campo a mostrar en el ComboBox. Para ello hice una clase sencilla y una <a href="http://cromo.cda-ie.es/2009/07/31/mantener-actualizados-unos-combobox-ii/" target="_blank">BindingList personalizada</a> con métodos de ordenación específicos. También una enumeración con todas las tablas.</span></p>
<p style="text-align: justify"><span style="font-family: Verdana; font-size: 10pt">Junté todo en una colección tipo Dictionary. Sus pares de valores eran el valor de la enumeración (que identifica la tabla) y la BindingList personalizada con el conjunto de datos de la tabla. Ahora sólo queda pasar ese Dictionary a cada UserControl y que éste enlace cada ComboBox a la BindingList correspondiente. ¿Cómo? Pues, por ejemplo, creando otro Dictionary que para cada tabla (valor de la enumeración) tenga el ComboBox correspondiente. Así:</span> </p>
<table border="0" width="90%" align="center" bgcolor="#e6e6fa">
<tr>
<td>
<pre style="font-family: 'Courier New', Courier, monospace; font-size:9pt"><span style="color:#0000FF">Private</span> _MisCombos <span style="color:#0000FF">As</span> <span style="color:#0000FF">New</span> Dictionary(<span style="color:#0000FF">Of</span> enTablas, ComboBox)</pre>
</td>
</tr>
</table>
<p style="text-align: justify"><span style="font-family: Verdana; font-size: 10pt">Y en el constructor del UserControl:</span></p>
<table border="0" width="90%" align="center" bgcolor="#e6e6fa">
<tr>
<td>
<pre style="font-family: 'Courier New', Courier, monospace; font-size:9pt"><span style="color:#0000FF">With</span> _MisCombos
    .Add(enTablas.Fansub, cboFansub)
    .Add(enTablas.Subtitulos, cboSubtitulos)
    .Add(enTablas.Archivador, cboArchivador)
    .Add(enTablas.Video, cboCodecVideo)
    .Add(enTablas.Audio, cboCodecAudio)
    .Add(enTablas.Valoracion, cboRValoracion)
    .Add(enTablas.TipoArchivo, cboContenedor)
    .Add(enTablas.Soporte, cboSoporte)
    .Add(enTablas.Calidad, cboCalidad)
    .Add(enTablas.Resolucion, cboResolucion)
<span style="color:#0000FF">End</span> <span style="color:#0000FF">With</span></pre>
</td>
</tr>
</table>
<p style="text-align: justify"><span style="font-family: Verdana; font-size: 10pt">Lo siguiente es pasarle al UserControl el Dictionary con el contenido de las tablas, ya sea mediante una propiedad, un método o un constructor con parámetros. Supongamos que a ese Dictionary lo llamamos _LoQueHayEnLosCombos. Recordemos: ese Dictionary está formado por la enumeración de las tablas, enTablas, y por la BindingList personalizada, lista de una clase con dos propiedades, Id y Descripcion. Ya con todo eso junto, el enlace de cada combo con su tabla correspondiente se puede hacer así:</span></p>
<table border="0" width="90%" align="center" bgcolor="#e6e6fa">
<tr>
<td>
<pre style="font-family: 'Courier New', Courier, monospace; font-size:9pt"><span style="color:#008000">'Y, ahora, la magia:</span>
<span style="color:#0000FF">For</span> <span style="color:#0000FF">Each</span> Combo <span style="color:#0000FF">As</span> KeyValuePair(<span style="color:#0000FF">Of</span> enTablas, ComboBox) <span style="color:#0000FF">In</span> _MisCombos
    Combo.Value.DataSource = _LoQueHayEnLosCombos(Combo.Key)
    Combo.Value.DisplayMember = <span style="color:#B22222">"Descripcion"</span>
    Combo.Value.ValueMember = <span style="color:#B22222">"Id"</span>
<span style="color:#0000FF">Next</span></pre>
</td>
</tr>
</table>
<p style="text-align: justify"><span style="font-family: Verdana; font-size: 10pt">En fin, un ejemplo un poco tonto de cómo relacionar colecciones mediante Dictionary que compartan la misma Key. Si a alguien le sirve de algo, como siempre, me alegro.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://cromo.cda-ie.es/2009/12/24/jugando-con-colecciones-dictionary/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Usando un TableAdapterManager</title>
		<link>http://cromo.cda-ie.es/2009/11/10/usando-un-tableadaptermanager/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=usando-un-tableadaptermanager</link>
		<comments>http://cromo.cda-ie.es/2009/11/10/usando-un-tableadaptermanager/#comments</comments>
		<pubDate>Tue, 10 Nov 2009 22:21:52 +0000</pubDate>
		<dc:creator>Cubano</dc:creator>
				<category><![CDATA[Visual Basic 2008]]></category>

		<guid isPermaLink="false">http://cromo.cda-ie.es/?p=218</guid>
		<description><![CDATA[Una de las entradas de este blog que más visitas registra hace referencia a un error en el código generado de los TableAdapterManager, un componente de acceso a datos para usarlo junto con datasets tipados y sus respectivos tableadapters. Dicho error fue solucionado en el SP1 de Visual Studio y de las versiones Express, por [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Una de las <a href="http://cromo.cda-ie.es/2008/05/27/tableadaptermanager/" target="_blank">entradas</a> de este blog que más visitas registra hace referencia a un error en el código generado de los </span><span style="font-family:Courier New">TableAdapterManager</span><span style="font-family:Verdana">, un componente de acceso a datos para usarlo junto con datasets tipados y sus respectivos tableadapters. <a href="http://cromo.cda-ie.es/2008/08/01/a-vueltas-con-el-tableadaptermanager/" target="_blank">Dicho error</a> fue solucionado en el SP1 de Visual Studio y de las versiones Express, por lo que ya creía el tema olvidado. Sin embargo, parece que su uso despierta bastantes dudas, así que me vais a permitir que retome el tema con un pequeño ejemplo.<br />
</span></span></p>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Un </span><span style="font-family:Courier New">TableAdapterManager</span><span style="font-family:Verdana"> es un componente que se genera al crear un dataset tipado. Por lo tanto, si no usamos un dataset tipado ni necesitamos saber que tal cosa existe. Un </span><span style="font-family:Courier New">TableAdapterManager</span><span style="font-family:Verdana"> automatiza el proceso de actualizar varias tablas relacionadas, manteniendo (o intentándolo) la integridad de los datos al hacer los update, insert y deletes en el orden apropiado. Hemos dicho que el </span><span style="font-family:Courier New">TableAdapterManager</span><span style="font-family:Verdana"> se crea con un dataset tipado, por lo que sólo tendrá utilidad si este dataset tipado tiene varias tablas relacionadas.<br />
</span></span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Veamos el siguiente ejemplo, un dataset tipado, SeriesDataSet, con tres tablas: Series, Género y GeneroSerie. GeneroSerie es la tabla que permite la relación n:m entre géneros y series (una serie puede tener varios géneros, puede ser un drama romántico de ciencia ficción, por ejemplo).<br />
</span></p>
<p><span id="more-218"></span></p>
<p style="text-align: center;"><img style="border: 0pt none; margin: 5px;" src="http://i114.photobucket.com/albums/n280/ercubano/Foro/dsSeries.jpg" alt="" width="450" height="351" /><br />
<span style="font-family:Courier New; font-size:10pt"><em>SeriesDataSet</em></span></p>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Vamos a suponer que tenemos un formulario donde el usuario podrá dar de alta, modificar y eliminar series y sus géneros. Es decir, variarán los datos de las datatables Series y GeneroSerie. A la hora de pasar esos cambios de datos a la base de datos debemos tener presente la relación de las tablas. Así, a la hora de insertar nuevas filas deberemos insertar primero las series y luego sus géneros, pero a la hora de borrar deberemos borrar primero los géneros de la serie y luego la serie. Esto significa que no podemos hacer un procedimiento genérico llamando alegremente a los métodos </span><span style="font-family:Courier New">Update</span><span style="font-family:Verdana"> de los respectivos tableadapters. Pero podemos usar el método </span><span style="font-family:Courier New">UpdateAll</span><span style="font-family:Verdana"> del </span><span style="font-family:Courier New">TableAdapterManager</span><span style="font-family:Verdana"> y que sea él quien se coma el marrón. Algo así:</span></span></p>
<table border="0" width="90%" align="center" bgcolor="#e6e6fa">
<tbody>
<tr>
<td>
<pre style="font-family: 'Courier New', Courier, monospace; font-size:9pt"><span style="color:#0000FF">Public</span> <span style="color:#0000FF">Function</span> GuardaDatos(<span style="color:#0000FF">ByVal</span> dsSeries <span style="color:#0000FF">As</span> SeriesDataSet) <span style="color:#0000FF">As</span> <span style="color:#0000FF">Integer</span>
    <span style="color:#0000FF">Dim</span> Result <span style="color:#0000FF">As</span> <span style="color:#0000FF">Integer</span>
    <span style="color:#0000FF">Dim</span> tamSeries <span style="color:#0000FF">As</span> <span style="color:#0000FF">New</span> SeriesDataSetTableAdapters.TableAdapterManager
    <span style="color:#0000FF">Dim</span> taSeries <span style="color:#0000FF">As</span> <span style="color:#0000FF">New</span> SeriesDataSetTableAdapters.SeriesTableAdapter
    <span style="color:#0000FF">Dim</span> taGeneroSerie <span style="color:#0000FF">As</span> <span style="color:#0000FF">New</span> SeriesDataSetTableAdapters.GeneroSerieTableAdapter
    <span style="color:#0000FF">Using</span> cnConexion <span style="color:#0000FF">As</span> <span style="color:#0000FF">New</span> SqlServerCe.SqlCeConnection( _
                                <span style="color:#0000FF">My</span>.Settings.DefaultConnectionString)
        <span style="color:#0000FF">Try</span>
            <span style="color:#008000">'Le pasamos los TableAdapters al TableAdapterManager</span>
            tamSeries.SeriesTableAdapter = taSeries
            tamSeries.GeneroSerieTableAdapter = taGeneroSerie
            <span style="color:#008000">'Le pasamos la conexión que vamos a usar</span>
            <span style="color:#008000">'(De no hacerlo, se crearía la suya propia)</span>
            tamSeries.Connection = cnConexion
            <span style="color:#008000">'Abrimos la conexión. En VB2008 sin SP1 daría error</span>
            cnConexion.Open()
            Result = tamSeries.UpdateAll(dsSeries)
        <span style="color:#0000FF">Catch</span> ex <span style="color:#0000FF">As</span> Exception
            <span style="color:#0000FF">Throw</span> ex
        <span style="color:#0000FF">Finally</span>
            cnConexion.Close()
        <span style="color:#0000FF">End</span> <span style="color:#0000FF">Try</span>
    <span style="color:#0000FF">End</span> <span style="color:#0000FF">Using</span>
    <span style="color:#0000FF">Return</span> Result
<span style="color:#0000FF">End</span> <span style="color:#0000FF">Function</span></pre>
</td>
</tr>
</tbody>
</table>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Resumiendo: hemos creado una instancia del </span><span style="font-family:Courier New">TableAdapterManager</span><span style="font-family:Verdana"> que VB2008 ha creado junto con los tableadapters del dataset tipado </span><span style="font-family:Courier New">SeriesDataSet</span><span style="font-family:Verdana">. El </span><span style="font-family:Courier New">TableAdapterManager</span><span style="font-family:Verdana"> necesita que le pasemos los tableadapters con los que va a trabajar, y eso es lo que hemos hecho. Como está tan tipado como el dataset, las datatables y los tableadapters, tiene tres propiedades distintas, cada una esperando su tableadapter. Habíamos dicho que sólo íbamos a modificar valores en la tabla </span><span style="font-family:Courier New">SeriesDataTable</span><span style="font-family:Verdana"> y en la tabla </span><span style="font-family:Courier New">GeneroSerieDataTable</span><span style="font-family:Verdana">, por lo que sólo necesitamos sus dos tableadapters correspondientes. De </span><span style="font-family:Courier New">GeneroTableAdapter</span><span style="font-family:Verdana"> aquí nos olvidamos.<br />
</span></span></p>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Ya sólo nos queda llamar al método </span><span style="font-family:Courier New"><strong>UpdateAll</strong></span><span style="font-family:Verdana"> pasándole el dataset de Series y listo. El </span><span style="font-family:Courier New">TableAdapterManager</span><span style="font-family:Verdana"> no tiene mucho más misterio. Básicamente trabajaremos únicamente con las propiedades de los respectivos tableadapters, el objeto </span><span style="font-family:Courier New">Connection</span><span style="font-family:Verdana">, el método </span><span style="font-family:Courier New">UpdateAll</span><span style="font-family:Verdana"> y la propiedad </span><span style="font-family:Courier New"><strong>UpdateOrder</strong></span><span style="font-family:Verdana">. UpdateOrder tiene dos valores posibles (y autoexplicativos): </span><span style="font-family:Courier New"><strong>UpdateInsertDelete</strong></span><span style="font-family:Verdana"><strong><br />
</strong>(primero hace los update, luego los insert y por último los delete) e </span><span style="font-family:Courier New"><strong>InsertUpdateDelete</strong></span><span style="font-family:Verdana">, que hace lo obvio. Podemos ver lo que hace el método UpdateAll, en todo caso, con el habitual &#8220;Ir a definición&#8221;.<br />
</span></span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Y no hay más. Está bien para situaciones sencillitas, y se queda corto en otras. No lo he usado mucho, pero las veces que lo he metido me ha permitido ahorrarme un tiempecito que me ha venido bien para otras cosas. </span></p>
]]></content:encoded>
			<wfw:commentRss>http://cromo.cda-ie.es/2009/11/10/usando-un-tableadaptermanager/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Mantener actualizados unos ComboBox (II)</title>
		<link>http://cromo.cda-ie.es/2009/07/31/mantener-actualizados-unos-combobox-ii/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mantener-actualizados-unos-combobox-ii</link>
		<comments>http://cromo.cda-ie.es/2009/07/31/mantener-actualizados-unos-combobox-ii/#comments</comments>
		<pubDate>Fri, 31 Jul 2009 17:32:27 +0000</pubDate>
		<dc:creator>Cubano</dc:creator>
				<category><![CDATA[Visual Basic 2008]]></category>

		<guid isPermaLink="false">http://cromo.cda-ie.es/?p=156</guid>
		<description><![CDATA[No tenía intención de volver sobre este tema pero, la verdad, tampoco tengo nada más que escribir. Y, al final, fue un problema curioso cuya resolución no me quedó tan elegante como a mí me hubiera gustado. El primer problema que me dio la solución que comentaba fue cuando intenté ordenar el contenido de la [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">No tenía intención de volver sobre <a href="http://cromo.cda-ie.es/2009/07/02/mantener-actualizados-unos-combobox/" target="_blank">este tema</a> pero, la verdad, tampoco tengo nada más que escribir. Y, al final, fue un problema curioso cuya resolución no me quedó tan elegante como a mí me hubiera gustado. El primer problema que me dio la solución que comentaba fue cuando intenté ordenar el contenido de la </span><span style="font-family:Courier New">BindingList</span><span style="font-family:Verdana">. Mi gozo en un pozo: la </span><span style="font-family:Courier New">BindingList</span><span style="font-family:Verdana"> no ordena. Me resulta chocante que la </span><span style="font-family:Courier New">BindingList</span><span style="font-family:Verdana">, que se supone va mejor para enlace a datos, no ordene ni busque, y una </span><span style="font-family:Courier New">List</span><span style="font-family:Verdana"> sí. De hecho, por internet e incluso en la misma documentación de MSDN encontramos clases derivadas de </span><span style="font-family:Courier New">BindingList</span><span style="font-family:Verdana"> que ordenan y/o buscan. De hecho, encontré una para un caso general que me ha gustado mucho y me la he guardado, pero para esta aplicación he preferido usar una clase preparada para la ocasión.<br />
</span></span></p>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Partíamos, recuerdo, de una clase muy sencilla, </span><span style="font-family:Courier New">IdMasDescripcion</span><span style="font-family:Verdana">, con dos propiedades, </span><span style="font-family:Courier New">Id</span><span style="font-family:Verdana"> de tipo </span><span style="font-family:Courier New">Integer</span><span style="font-family:Verdana"> que se corresponde a la clave primaria, y </span><span style="font-family:Courier New">Descripcion</span><span style="font-family:Verdana"> de tipo </span><span style="font-family:Courier New">String</span><span style="font-family:Verdana">. La clase, además, implementa la interfaz </span><span style="font-family:Courier New">IComparable(Of T)</span><span style="font-family:Verdana">, y el método </span><span style="font-family:Courier New">CompareTo</span><span style="font-family:Verdana"> lo que hace es comparar las descripciones. Lo que voy a hacer, entonces, es una </span><span style="font-family:Courier New">BindingList(Of IdMasDescripcion)</span><span style="font-family:Verdana"> personalizada que sea capaz de ordenarse. Pero no siempre va a estar ordenada (depende de qué tabla muestre) y la ordenación puede ser alfabética o por resoluciones (de momento; en un futuro puede que me haga falta un tercer tipo). Voy a necesitar un método para ordenar (</span><span style="font-family:Courier New">Sort</span><span style="font-family:Verdana">), y dos campos que me indiquen si la colección está ordenada (</span><span style="font-family:Courier New">IsSorted</span><span style="font-family:Verdana">) y si hay que ordenarla (</span><span style="font-family:Courier New">ToSort</span><span style="font-family:Verdana">):<br />
</span></span><br />
<span id="more-156"></span></p>
<table border="0" width="90%" align="center" bgcolor="#e6e6fa">
<tbody>
<tr>
<td>
<pre style="font-family: 'Courier New', Courier, monospace; font-size:9pt"><span style="color: #0000FF">Imports</span> System.ComponentModel
<span style="color: #0000FF">Imports</span> CdA.Comun

<span style="color: #0000FF">Public</span> <span style="color: #0000FF">Class</span> ReleasesCombosBinding
    <span style="color: #0000FF">Inherits</span> System.ComponentModel.BindingList(<span style="color: #0000FF">Of</span> IdMasDescripcion)
    <span style="color: #0000FF">Public</span> <span style="color: #0000FF">Enum</span> TipoOrden <span style="color: #0000FF">As</span> <span style="color: #0000FF">Integer</span>
        Alfabetico
        Resolucion
    <span style="color: #0000FF">End</span> <span style="color: #0000FF">Enum</span>
    <span style="color: #0000FF">Private</span> _IsSorted <span style="color: #0000FF">As</span> <span style="color: #0000FF">Boolean</span> = <span style="color: #0000FF">False</span>
    <span style="color: #0000FF">Private</span> _ToSort <span style="color: #0000FF">As</span> <span style="color: #0000FF">Boolean</span> = <span style="color: #0000FF">False</span>
    <span style="color: #0000FF">Private</span> _TipoSort <span style="color: #0000FF">As</span> TipoOrden = TipoOrden.Alfabetico

    <span style="color: #0000FF">Protected</span> <span style="color: #0000FF">Overrides</span> <span style="color: #0000FF">Sub</span> ClearItems()
        <span style="color: #0000FF">Me</span>.IsSorted = <span style="color: #0000FF">False</span>
        <span style="color: #0000FF">MyBase</span>.ClearItems()
    <span style="color: #0000FF">End</span> <span style="color: #0000FF">Sub</span>

    <span style="color: #5C5C5C">''' &lt;summary&gt;</span>
    <span style="color: #5C5C5C">''' Ordena la lista subyacente de forma ascendente</span>
    <span style="color: #5C5C5C">''' &lt;/summary&gt;</span>
    <span style="color: #0000FF">Public</span> <span style="color: #0000FF">Sub</span> Sort()
        <span style="color: #0000FF">Dim</span> items <span style="color: #0000FF">As</span> List(<span style="color: #0000FF">Of</span> IdMasDescripcion) = <span style="color: #0000FF">TryCast</span>(<span style="color: #0000FF">Me</span>.Items,  _
                                            List(<span style="color: #0000FF">Of</span> IdMasDescripcion))
        <span style="color: #0000FF">If</span> items <span style="color: #0000FF">IsNot</span> <span style="color: #0000FF">Nothing</span> <span style="color: #0000FF">Then</span>
            <span style="color: #0000FF">Select</span> <span style="color: #0000FF">Case</span> <span style="color: #0000FF">Me</span>._TipoSort
                <span style="color: #0000FF">Case</span> TipoOrden.Alfabetico
                    items.Sort()
                <span style="color: #0000FF">Case</span> TipoOrden.Resolucion
                    <span style="color: #008000">'(...)</span>
            <span style="color: #0000FF">End</span> <span style="color: #0000FF">Select</span>
            <span style="color: #0000FF">Me</span>.IsSorted = <span style="color: #0000FF">True</span>
        <span style="color: #0000FF">Else</span>

        <span style="color: #0000FF">End</span> <span style="color: #0000FF">If</span>
        <span style="color: #0000FF">Me</span>.OnListChanged(<span style="color: #0000FF">New</span> ListChangedEventArgs(ListChangedType.Reset, -1))
    <span style="color: #0000FF">End</span> <span style="color: #0000FF">Sub</span>

#<span style="color: #0000FF">Region</span> <span style="color: #B22222">" Propiedades públicas "</span>
    <span style="color: #5C5C5C">''' &lt;summary&gt;</span>
    <span style="color: #5C5C5C">''' Devuelve si la lista está ordenada o no</span>
    <span style="color: #5C5C5C">''' &lt;/summary&gt;</span>
    <span style="color: #0000FF">Public</span> <span style="color: #0000FF">Property</span> IsSorted() <span style="color: #0000FF">As</span> <span style="color: #0000FF">Boolean</span>
        <span style="color: #0000FF">Get</span>
            <span style="color: #0000FF">Return</span> <span style="color: #0000FF">Me</span>._IsSorted
        <span style="color: #0000FF">End</span> <span style="color: #0000FF">Get</span>
        <span style="color: #0000FF">Protected</span> <span style="color: #0000FF">Set</span>(<span style="color: #0000FF">ByVal</span> value <span style="color: #0000FF">As</span> <span style="color: #0000FF">Boolean</span>)
            <span style="color: #0000FF">Me</span>._IsSorted = value
        <span style="color: #0000FF">End</span> <span style="color: #0000FF">Set</span>
    <span style="color: #0000FF">End</span> <span style="color: #0000FF">Property</span>

    <span style="color: #5C5C5C">''' &lt;summary&gt;</span>
    <span style="color: #5C5C5C">''' Devuelve o establece si la lista ha de ser ordenada.</span>
    <span style="color: #5C5C5C">''' &lt;/summary&gt;</span>
    <span style="color: #5C5C5C">''' &lt;value&gt;&lt;/value&gt;</span>
    <span style="color: #5C5C5C">''' &lt;returns&gt;&lt;/returns&gt;</span>
    <span style="color: #5C5C5C">''' &lt;remarks&gt;&lt;/remarks&gt;</span>
    <span style="color: #0000FF">Public</span> <span style="color: #0000FF">Property</span> ToSort() <span style="color: #0000FF">As</span> <span style="color: #0000FF">Boolean</span>
        <span style="color: #0000FF">Get</span>
            <span style="color: #0000FF">Return</span> <span style="color: #0000FF">Me</span>._ToSort
        <span style="color: #0000FF">End</span> <span style="color: #0000FF">Get</span>
        <span style="color: #0000FF">Set</span>(<span style="color: #0000FF">ByVal</span> value <span style="color: #0000FF">As</span> <span style="color: #0000FF">Boolean</span>)
            <span style="color: #0000FF">Me</span>._ToSort = value
        <span style="color: #0000FF">End</span> <span style="color: #0000FF">Set</span>
    <span style="color: #0000FF">End</span> <span style="color: #0000FF">Property</span>

    <span style="color: #0000FF">Public</span> <span style="color: #0000FF">Property</span> TipoSort() <span style="color: #0000FF">As</span> TipoOrden
        <span style="color: #0000FF">Get</span>
            <span style="color: #0000FF">Return</span> <span style="color: #0000FF">Me</span>._TipoSort
        <span style="color: #0000FF">End</span> <span style="color: #0000FF">Get</span>
        <span style="color: #0000FF">Set</span>(<span style="color: #0000FF">ByVal</span> value <span style="color: #0000FF">As</span> TipoOrden)
            <span style="color: #0000FF">Me</span>._TipoSort = value
        <span style="color: #0000FF">End</span> <span style="color: #0000FF">Set</span>
    <span style="color: #0000FF">End</span> <span style="color: #0000FF">Property</span>
#<span style="color: #0000FF">End</span> <span style="color: #0000FF">Region</span>

#<span style="color: #0000FF">Region</span> <span style="color: #B22222">" Métodos privados "</span>
    <span style="color: #0000FF">Private</span> <span style="color: #0000FF">Function</span> ValorNumL(<span style="color: #0000FF">ByVal</span> Resolucion <span style="color: #0000FF">As</span> <span style="color: #0000FF">String</span>) <span style="color: #0000FF">As</span> <span style="color: #0000FF">Integer</span>
    <span style="color: #0000FF">End</span> <span style="color: #0000FF">Function</span>
    <span style="color: #0000FF">Private</span> <span style="color: #0000FF">Function</span> ValorNumA(<span style="color: #0000FF">ByVal</span> Resolucion <span style="color: #0000FF">As</span> <span style="color: #0000FF">String</span>) <span style="color: #0000FF">As</span> <span style="color: #0000FF">Integer</span>

    <span style="color: #0000FF">End</span> <span style="color: #0000FF">Function</span>
#<span style="color: #0000FF">End</span> <span style="color: #0000FF">Region</span>

<span style="color: #0000FF">End</span> <span style="color: #0000FF">Class</span></pre>
</td>
</tr>
</tbody>
</table>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">El código que falta, marcado con (…) en el método </span><span style="font-family:Courier New">Sort</span><span style="font-family:Verdana"> y las dos funciones en blanco, se corresponden con la <a href="http://cromo.cda-ie.es/2009/07/13/ordenando-por-resoluciones/" target="_blank">ordenación por resoluciones</a>.  De la clase en sí, tenemos que la propiedad </span><span style="font-family:Courier New">IsSorted</span><span style="font-family:Verdana"> sólo puede cambiar su valor desde dentro de la clase: al ordenar la colección o al vaciarla. Por otra parte, el método Sort termina provocando el evento </span><span style="font-family:Courier New">ListChanged</span><span style="font-family:Verdana">, necesario para que todo el mundo que trabaje con esta colección se entere de que ha cambiado.<br />
</span></span></p>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Vayamos al formulario de Series, que es para el que nos hace falta esta clase. Vamos a tener una </span><span style="font-family:Courier New">ReleasesCombosBinding</span><span style="font-family:Verdana"> por cada combo que hay en una pestaña, y que se corresponde con una tabla de la base de datos. Para tenerlo más ordenado, voy a aprovechar una enumeración con toda la lista de tablas de la base de datos, llamada </span><span style="font-family:Courier New">enTablas</span><span style="font-family:Verdana"> y definir lo siguiente:<br />
</span></span></p>
<table border="0" width="90%" align="center" bgcolor="#e6e6fa">
<tbody>
<tr>
<td>
<pre style="font-family: 'Courier New', Courier, monospace; font-size:9pt"><span style="color: #0000FF">Private</span> CombosReleases <span style="color: #0000FF">As</span> <span style="color: #0000FF">New</span> Dictionary(<span style="color: #0000FF">Of</span> enTablas, ReleasesCombosBinding)</pre>
</td>
</tr>
</tbody>
</table>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">El primer &#8220;llenado&#8221; lo hago en la capa inferior. El método recibe el diccionario y se ocupa de llenarlo para cada tabla. Como la aplicación no es muy grande, en su día la diseñé en dos capas y el método en cuestión queda embutido en la clase de acceso a datos de una forma un poco extraña pero (ojo, no está todo el código):</span></p>
<table border="0" width="90%" align="center" bgcolor="#e6e6fa">
<tbody>
<tr>
<td>
<pre style="font-family: 'Courier New', Courier, monospace; font-size:9pt"><span style="color: #0000FF">Public</span> <span style="color: #0000FF">Function</span> LeerDatosCombosReleases() <span style="color: #0000FF">As</span> Dictionary(<span style="color: #0000FF">Of</span> enTablas,  _
                                                 ReleasesCombosBinding)
    <span style="color: #0000FF">Dim</span> dicCombos <span style="color: #0000FF">As</span> <span style="color: #0000FF">New</span> Dictionary(<span style="color: #0000FF">Of</span> enTablas, ReleasesCombosBinding)
    <span style="color: #0000FF">Dim</span> HeConectado <span style="color: #0000FF">As</span> <span style="color: #0000FF">Boolean</span> = <span style="color: #0000FF">False</span>
    <span style="color: #0000FF">Try</span>
        <span style="color: #0000FF">If</span> <span style="color: #0000FF">Me</span>.Conexion.State = ConnectionState.Closed <span style="color: #0000FF">Then</span>
            HeConectado = <span style="color: #0000FF">Me</span>.Conectar()
        <span style="color: #0000FF">End</span> <span style="color: #0000FF">If</span>
        <span style="color: #008000">'Y ahora el lío padre. Necesitamos una variante de LlenarCombo </span>
        <span style="color: #008000">'a la que, pasándole el nombre de la tabla, nos devuelva un </span>
        <span style="color: #008000">'ReleasesComboBinding de esos con todos los valores. Llamaremos </span>
        <span style="color: #008000">'a esa función para cada puñetera tabla para rellenar el dictionary.</span>
        <span style="color: #008000">'Las tablas:</span>
        <span style="color: #008000">'Archivador</span>
        dicCombos.Add(enTablas.Archivador, _
                      <span style="color: #0000FF">Me</span>.LlenarLista(enTablas.Archivador.ToString, <span style="color: #0000FF">True</span>))
        <span style="color: #008000">'Audio</span>
        dicCombos.Add(enTablas.Audio, <span style="color: #0000FF">Me</span>.LlenarLista(enTablas.Audio.ToString, _
                                                     <span style="color: #0000FF">True</span>))
        <span style="color: #008000">'Calidad</span>
        dicCombos.Add(enTablas.Calidad, <span style="color: #0000FF">Me</span>.LlenarLista(enTablas.Calidad.ToString))
        <span style="color: #008000">'Fansub</span>
        dicCombos.Add(enTablas.Fansub, <span style="color: #0000FF">Me</span>.LlenarLista(enTablas.Fansub.ToString, _
                                                      <span style="color: #0000FF">True</span>))
        <span style="color: #008000">'Resolucion</span>
        dicCombos.Add(enTablas.Resolucion, _
                      <span style="color: #0000FF">Me</span>.LlenarLista(enTablas.Resolucion.ToString, _
                      <span style="color: #0000FF">True</span>, ReleasesCombosBinding.TipoOrden.Resolucion))
        <span style="color: #008000">'Soporte</span>
        dicCombos.Add(enTablas.Soporte, <span style="color: #0000FF">Me</span>.LlenarLista(enTablas.Soporte.ToString))
        <span style="color: #008000">'(...)</span>
    <span style="color: #0000FF">Finally</span>
        <span style="color: #0000FF">If</span> HeConectado <span style="color: #0000FF">Then</span>
            <span style="color: #0000FF">Me</span>.Desconectar()
        <span style="color: #0000FF">End</span> <span style="color: #0000FF">If</span>
    <span style="color: #0000FF">End</span> <span style="color: #0000FF">Try</span>
    <span style="color: #0000FF">Return</span> dicCombos
<span style="color: #0000FF">End</span> <span style="color: #0000FF">Function</span></pre>
</td>
</tr>
</tbody>
</table>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Donde <span style="font-family:Courier New">LlenarLista</span> lo que hace es crear el nuevo <span style="font-family:Courier New">ReleasesComboBinding</span> y rellenarla, ordenando o no según se le indique. El método recibe el nombre de las tablas como parámetro, que, casualmente, coincide con el nombre dado a cada elemento de la enumeración de tablas. Realmente hay dos métodos <span style="font-family:Courier New">LlenarLista</span>, una función y un procedimiento. La función crea la colección y la devuelve en su nombre, mientras que el procedimiento recibe la colección como parámetro, lo limpia, rellena y ordena si debe. Este procedimiento será al que llame a la hora de actualizar cada <span style="font-family:Courier New">ReleasesComboBinding</span>.</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Aquí tenemos la función:</span></p>
<table border="0" width="90%" align="center" bgcolor="#e6e6fa">
<tbody>
<tr>
<td>
<pre style="font-family: 'Courier New', Courier, monospace; font-size:9pt"><span style="color: #5C5C5C">''' &lt;summary&gt;</span>
<span style="color: #5C5C5C">''' Vuelca el contenido de la tabla indicada en el parámetro</span>
<span style="color: #5C5C5C">''' a una lista que guarda el campo identificador y el descriptor</span>
<span style="color: #5C5C5C">''' (los dos primeros) de esa tabla, creando una nueva lista.</span>
<span style="color: #5C5C5C">''' &lt;/summary&gt;</span>
<span style="color: #5C5C5C">''' &lt;param name=</span>Tabla<span style="color: #B22222">"&gt;Nombre de la tabla&lt;/param&gt;"</span>
<span style="color: #0000FF">Public</span> <span style="color: #0000FF">Function</span> LlenarLista(<span style="color: #0000FF">ByVal</span> Tabla <span style="color: #0000FF">As</span> <span style="color: #0000FF">String</span>, _
            <span style="color: #0000FF">Optional</span> <span style="color: #0000FF">ByVal</span> Ordenar <span style="color: #0000FF">As</span> <span style="color: #0000FF">Boolean</span> = <span style="color: #0000FF">False</span>, _
            <span style="color: #0000FF">Optional</span> <span style="color: #0000FF">ByVal</span> Como <span style="color: #0000FF">As</span> ReleasesCombosBinding.TipoOrden = _
            ReleasesCombosBinding.TipoOrden.Alfabetico) <span style="color: #0000FF">As</span> ReleasesCombosBinding
    <span style="color: #0000FF">Dim</span> MisDatos <span style="color: #0000FF">As</span> <span style="color: #0000FF">New</span> ReleasesCombosBinding
    MisDatos.ToSort = Ordenar
    MisDatos.TipoSort = Como
    <span style="color: #0000FF">Try</span>
        <span style="color: #0000FF">Me</span>.LlenarLista(Tabla, MisDatos)
    <span style="color: #0000FF">Catch</span> ex <span style="color: #0000FF">As</span> Exception
        <span style="color: #0000FF">Throw</span> ex
    <span style="color: #0000FF">End</span> <span style="color: #0000FF">Try</span>
    <span style="color: #0000FF">Return</span> MisDatos
<span style="color: #0000FF">End</span> <span style="color: #0000FF">Function</span></pre>
</td>
</tr>
</tbody>
</table>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Y aquí el procedimiento:</span></p>
<table border="0" width="90%" align="center" bgcolor="#e6e6fa">
<tbody>
<tr>
<td>
<pre style="font-family: 'Courier New', Courier, monospace; font-size:9pt"><span style="color: #0000FF">Public</span> <span style="color: #0000FF">Sub</span> LlenarLista(<span style="color: #0000FF">ByVal</span> Tabla <span style="color: #0000FF">As</span> <span style="color: #0000FF">String</span>, _
                       <span style="color: #0000FF">ByVal</span> MisDatos <span style="color: #0000FF">As</span> ReleasesCombosBinding)
    <span style="color: #0000FF">Dim</span> drDatos <span style="color: #0000FF">As</span> SqlServerCe.SqlCeDataReader
    <span style="color: #0000FF">Dim</span> Comando <span style="color: #0000FF">As</span> SqlServerCe.SqlCeCommand
    <span style="color: #0000FF">Dim</span> tbTabla <span style="color: #0000FF">As</span> DataTable
    <span style="color: #0000FF">Dim</span> HeConectado <span style="color: #0000FF">As</span> <span style="color: #0000FF">Boolean</span> = <span style="color: #0000FF">False</span>
    <span style="color: #0000FF">If</span> MisDatos <span style="color: #0000FF">Is</span> <span style="color: #0000FF">Nothing</span> <span style="color: #0000FF">Then</span>
        <span style="color: #0000FF">Exit</span> <span style="color: #0000FF">Sub</span>
    <span style="color: #0000FF">End</span> <span style="color: #0000FF">If</span>
    Comando = <span style="color: #0000FF">New</span> SqlServerCe.SqlCeCommand(<span style="color: #B22222">"SELECT * FROM "</span> &amp; Tabla, _
                                           <span style="color: #0000FF">Me</span>.Conexion)
    tbTabla = <span style="color: #0000FF">New</span> DataTable
    MisDatos.Clear()
    <span style="color: #0000FF">Try</span>
        <span style="color: #0000FF">If</span> <span style="color: #0000FF">Me</span>.Conexion.State = ConnectionState.Closed <span style="color: #0000FF">Then</span>
            HeConectado = <span style="color: #0000FF">Me</span>.Conectar()
        <span style="color: #0000FF">End</span> <span style="color: #0000FF">If</span>
        drDatos = Comando.ExecuteReader()
        tbTabla.Load(drDatos, LoadOption.OverwriteChanges)
        <span style="color: #0000FF">For</span> <span style="color: #0000FF">Each</span> Fila <span style="color: #0000FF">As</span> DataRow <span style="color: #0000FF">In</span> tbTabla.Rows
            MisDatos.Add(<span style="color: #0000FF">New</span> IdMasDescripcion(<span style="color: #0000FF">CInt</span>(Fila(0)), <span style="color: #0000FF">CStr</span>(Fila(1))))
        <span style="color: #0000FF">Next</span>
        drDatos.Close()
        <span style="color: #0000FF">If</span> MisDatos.ToSort <span style="color: #0000FF">Then</span>
            MisDatos.Sort()
        <span style="color: #0000FF">End</span> <span style="color: #0000FF">If</span>
    <span style="color: #0000FF">Catch</span> NoConexion <span style="color: #0000FF">As</span> InvalidOperationException
        <span style="color: #0000FF">Throw</span> NoConexion
    <span style="color: #0000FF">Catch</span> NoConexion <span style="color: #0000FF">As</span> Exception
        <span style="color: #0000FF">Throw</span> NoConexion
    <span style="color: #0000FF">Finally</span>
        Comando = <span style="color: #0000FF">Nothing</span>
        tbTabla = <span style="color: #0000FF">Nothing</span>
        <span style="color: #0000FF">If</span> HeConectado <span style="color: #0000FF">Then</span>
            <span style="color: #0000FF">Me</span>.Desconectar()
        <span style="color: #0000FF">End</span> <span style="color: #0000FF">If</span>
    <span style="color: #0000FF">End</span> <span style="color: #0000FF">Try</span>
<span style="color: #0000FF">End</span> <span style="color: #0000FF">Sub</span></pre>
</td>
</tr>
</tbody>
</table>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Y por hoy, ya me he cansado. La próxima cuento cómo trabajan el formulario y los combos de las pestañas con el diccionario. Lo que me recuerda que los chavales a los que di clase en primavera andaban algo liados con los arrays de estructuras. ¡y yo tengo aquí, básicamente, un array de arrays! La verdad es que cuando pienso en ello empieza a dolerme la cabeza.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://cromo.cda-ie.es/2009/07/31/mantener-actualizados-unos-combobox-ii/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ordenando por resoluciones</title>
		<link>http://cromo.cda-ie.es/2009/07/13/ordenando-por-resoluciones/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=ordenando-por-resoluciones</link>
		<comments>http://cromo.cda-ie.es/2009/07/13/ordenando-por-resoluciones/#comments</comments>
		<pubDate>Mon, 13 Jul 2009 17:15:47 +0000</pubDate>
		<dc:creator>Cubano</dc:creator>
				<category><![CDATA[Visual Basic 2005]]></category>
		<category><![CDATA[Visual Basic 2008]]></category>

		<guid isPermaLink="false">http://cromo.cda-ie.es/?p=139</guid>
		<description><![CDATA[Esto es una tontería del tipo tonterida, pero me ha llevado un ratito escribir el código, así que lo anoto aquí para cuando me vuelva a pasar, que entonces, seguramente, ya se me habrá olvidado y me tocará echar otro ratito y no me apetece. El problema es sencillo: hay que ordenar una lista de [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Esto es una tontería del tipo <em>tonterida</em>, pero me ha llevado un ratito escribir el código, así que lo anoto aquí para cuando me vuelva a pasar, que entonces, seguramente, ya se me habrá olvidado y me tocará echar otro ratito y no me apetece. El problema es sencillo: hay que ordenar una lista de elementos de forma no trivial. En este caso concreto, hay que ordenar por una propiedad de tipo </span><span style="font-family:Courier New">String</span><span style="font-family:Verdana">, cadena de caracteres, que va a contener resoluciones de imagen, esto es, dos valores numéricos separados por una &#8220;x&#8221;: 640&#215;480, 1024&#215;768 y así. También serviría para cualquier lista de pares de valores y se podría extender a situaciones más complejas, como coordenadas espaciales y cosas así. </span></span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Lo primero ha sido elegir el algoritmo de ordenación. Como van a ser pocos elementos, me he tirado a los sencillitos y, de estos, al de inserción, que es el único que soy capaz de desarrollar sin mirar la chuleta (el de la burbuja lo tengo atravesado). El proceso es muy simple: vamos ordenando por el primer valor. Si este es igual, pasamos a ordenar por el segundo valor. En este caso concreto, ordenamos por largo (primer valor) y si son iguales, por ancho. Para ello, lo primero que he hecho ha sido crearme dos funciones que me devuelvan el largo o el ancho a partir de la cadena:</span></p>
<p><span id="more-139"></span></p>
<table border="0" width="90%" align="center" bgcolor="#e6e6fa">
<tbody>
<tr>
<td>
<pre style="font-family: 'Courier New', Courier, monospace; font-size:9pt"><span style="color:#0000FF">Private</span> <span style="color:#0000FF">Function</span> ValorNumL(<span style="color:#0000FF">ByVal</span> Resolucion <span style="color:#0000FF">As</span> <span style="color:#0000FF">String</span>) <span style="color:#0000FF">As</span> <span style="color:#0000FF">Integer</span>
    <span style="color:#0000FF">Dim</span> pos <span style="color:#0000FF">As</span> <span style="color:#0000FF">Integer</span>
    pos = Resolucion.ToLower.IndexOf(<span style="color:#B22222">"x"</span>c)
    <span style="color:#0000FF">If</span> pos = -1 <span style="color:#0000FF">Then</span>
        ValorNumL = 0
    <span style="color:#0000FF">Else</span>
        <span style="color:#0000FF">Try</span>
            ValorNumL = <span style="color:#0000FF">CInt</span>(Strings.Left(Resolucion, pos))
        <span style="color:#0000FF">Catch</span> ex <span style="color:#0000FF">As</span> Exception
            ValorNumL = 0
        <span style="color:#0000FF">End</span> <span style="color:#0000FF">Try</span>
    <span style="color:#0000FF">End</span> <span style="color:#0000FF">If</span>
    <span style="color:#0000FF">Return</span> ValorNumL
<span style="color:#0000FF">End</span> <span style="color:#0000FF">Function</span>
<span style="color:#0000FF">Private</span> <span style="color:#0000FF">Function</span> ValorNumA(<span style="color:#0000FF">ByVal</span> Resolucion <span style="color:#0000FF">As</span> <span style="color:#0000FF">String</span>) <span style="color:#0000FF">As</span> <span style="color:#0000FF">Integer</span>
    <span style="color:#0000FF">Dim</span> pos <span style="color:#0000FF">As</span> <span style="color:#0000FF">Integer</span>
    pos = Resolucion.ToLower.IndexOf(<span style="color:#B22222">"x"</span>c)
    <span style="color:#0000FF">If</span> pos = -1 <span style="color:#0000FF">Then</span>
        ValorNumA = 0
    <span style="color:#0000FF">Else</span>
        <span style="color:#0000FF">Try</span>
            ValorNumA = <span style="color:#0000FF">CInt</span>(Strings.Right(Resolucion, _
                            Resolucion.Length - (pos + 1)))
        <span style="color:#0000FF">Catch</span> ex <span style="color:#0000FF">As</span> Exception
            ValorNumA = 0
        <span style="color:#0000FF">End</span> <span style="color:#0000FF">Try</span>
    <span style="color:#0000FF">End</span> <span style="color:#0000FF">If</span>
    <span style="color:#0000FF">Return</span> ValorNumA
<span style="color:#0000FF">End</span> <span style="color:#0000FF">Function</span></pre>
</td>
</tr>
</tbody>
</table>
<p style="text-align: justify"><span style="font-size:10pt"><span style="font-family:Verdana">Lo siguiente, implementar la búsqueda. Parto de una </span><span style="font-family:Courier New">List(of IdMasDescripcion)</span><span style="font-family:Verdana"> de nombre Resoluciones, donde </span><span style="font-family:Courier New">IdMasDescripcion</span><span style="font-family:Verdana"> es una clase que tiene una propiedad, </span><span style="font-family:Courier New">Descripcion</span><span style="font-family:Verdana">, de tipo </span><span style="font-family:Courier New">String</span><span style="font-family:Verdana">, que es por la que vamos a ordenar. </span></span></p>
<table border="0" width="90%" align="center" bgcolor="#e6e6fa">
<tbody>
<tr>
<td>
<pre style="font-family: 'Courier New', Courier, monospace; font-size:9pt"><span style="color:#0000FF">Dim</span> i, j, ElementoLargo, ElementoAncho, jLargo, jAncho <span style="color:#0000FF">As</span> <span style="color:#0000FF">Integer</span>
<span style="color:#0000FF">Dim</span> Elemento <span style="color:#0000FF">As</span> IdMasDescripcion
<span style="color:#0000FF">Dim</span> Menor <span style="color:#0000FF">As</span> <span style="color:#0000FF">Boolean</span> = <span style="color:#0000FF">False</span>
<span style="color:#0000FF">For</span> i = 1 <span style="color:#0000FF">To</span> Resoluciones.Count - 1
    Elemento = Resoluciones(i)
    ElementoLargo = ValorNumL(Elemento.Descripcion)
    ElementoAncho = ValorNumA(Elemento.Descripcion)
    j = i - 1
    <span style="color:#0000FF">Do</span>
        <span style="color:#008000">'1) Comparamos primero el largo(lado izdo):</span>
        jLargo = ValorNumL(Resoluciones(j).Descripcion)
        <span style="color:#0000FF">If</span> jLargo &gt; ElementoLargo <span style="color:#0000FF">Then</span>
            Resoluciones(j + 1) = Resoluciones(j)
            j = j - 1
            Menor = <span style="color:#0000FF">False</span>
        <span style="color:#0000FF">ElseIf</span> jLargo = ElementoLargo <span style="color:#0000FF">Then</span>
            <span style="color:#008000">'Si son iguales, ordenamos por el ancho</span>
            jAncho = ValorNumA(Resoluciones(j).Descripcion)
            <span style="color:#0000FF">If</span> jancho &gt; ElementoAncho <span style="color:#0000FF">Then</span>
                Resoluciones(j + 1) = Resoluciones(j)
                j = j - 1
                Menor = <span style="color:#0000FF">False</span>
            <span style="color:#0000FF">Else</span>
                Menor = <span style="color:#0000FF">True</span>
            <span style="color:#0000FF">End</span> <span style="color:#0000FF">If</span>
        <span style="color:#0000FF">Else</span>
            Menor = <span style="color:#0000FF">True</span>
        <span style="color:#0000FF">End</span> <span style="color:#0000FF">If</span>
    <span style="color:#0000FF">Loop</span> <span style="color:#0000FF">Until</span> j &lt; 0 <span style="color:#0000FF">OrElse</span> Menor
    Resoluciones(j + 1) = Elemento
<span style="color:#0000FF">Next</span></pre>
</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://cromo.cda-ie.es/2009/07/13/ordenando-por-resoluciones/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mantener actualizados unos ComboBox</title>
		<link>http://cromo.cda-ie.es/2009/07/02/mantener-actualizados-unos-combobox/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=mantener-actualizados-unos-combobox</link>
		<comments>http://cromo.cda-ie.es/2009/07/02/mantener-actualizados-unos-combobox/#comments</comments>
		<pubDate>Thu, 02 Jul 2009 09:54:48 +0000</pubDate>
		<dc:creator>Cubano</dc:creator>
				<category><![CDATA[Visual Basic 2005]]></category>
		<category><![CDATA[Visual Basic 2008]]></category>

		<guid isPermaLink="false">http://cromo.cda-ie.es/?p=131</guid>
		<description><![CDATA[Vamos con una de programación, que hace mucho que no cuento nada (básicamente, porque llevo unos meses sin programar; a ver si arranco motores). Me he puesto con mi aplicación de anime (un front-end para una base de datos de series, nada más, que me sirve de aprendizaje y experimentación). Ya me toca meter datos, [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Vamos con una de programación, que hace mucho que no cuento nada (básicamente, porque llevo unos meses sin programar; a ver si arranco motores). Me he puesto con mi aplicación de anime (un <em>front-end</em> para una base de datos de series, nada más, que me sirve de aprendizaje y experimentación). Ya me toca meter datos, sacar fallos, pulir el funcionamiento y terminar algunas funciones pendientes. Y recordar lo que estaba haciendo, que hace seis meses o así que no la tocaba.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Una de estas funciones, o funcionalidades, si lo preferís para no confundirlo con <em>functions</em>, es la de mantener actualizados una serie de comboboxes que hay en el formulario principal de las series. Estos comboboxes contienen los datos de una serie de tablas de la base de datos que se caracterizan por tener pocos datos: el formato de archivo, la resolución, el códec de vídeo… En otras circunstancias, los rellenaría usando mi clase <a href="http://cda-ie.es/2008/01/09/llenar-un-combobox/" target="_blank">RellenarCombo</a>, pero aquí se me presenta un problema curioso: como podéis ver en la imagen, hay una buena cantidad de comboboxes (una docena o así) que se corresponden a una serie de campos de las Releases (versiones) de una serie. El formulario muestra conjuntamente las series y sus releases, estando en la parte superior los datos de la serie y en la inferior, <em>en cero o más pestañas</em> los datos de las releases. O sea, tengo una docena de combos por cada pestaña.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Aquí empezaron mis problemas: ¿cómo rellenar esos combos y mantenerlos actualizados?</span></p>
<p><span id="more-131"></span></p>
<p style="text-align: center;"><img style="border: 0pt none; margin: 5px;" src="http://i114.photobucket.com/albums/n280/ercubano/Foro/pestagnarelease.jpg" alt="" width="400" height="200" /></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Lo primero que pensé fue no utilizar combos. En lugar de traerme los datos de las Releases (tabla) y ligarlos al ValueMember de cada combo, podía crearme una consulta que englobara la tabla de Releases y las tablas relacionadas. A la hora de modificar datos sí tendría que mostrar los combos y trabajar con la tabla de Releases, lo que me añadiría bastante complicación al código. Este sistema, más o menos, es el que estoy siguiendo en una aplicación para fábrica donde la modificación de los datos será mínima.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Otra opción era rellenar cada combo por su cuenta. En principio, lo normal sería tener sólo una release por serie, esto es, una pestaña, siendo tres o cuatro el número máximo. Así pues, podría hacer la carga del combo, digamos, de Tipo de archivo, una vez para cada pestaña. Esto no me gustaba por varias razones: la primera es la redundancia de datos en memoria. Si tengo tres veces el mismo ComboBox en el formulario (en tres pestañas) he cargado tres datatables para ligarlas a estos combos. La segunda es que a la hora de mantener esos datos actualizados (por ejemplo, si añado un nuevo tipo de archivo) tendría que comprobar cuántas pestañas hay y volver a cargar cada tabla ligada a cada combobox. Si tengo tres pestañas, el trabajo por tres. Y la tercera y más importante: no me parecía elegante.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Así que opté por cargar todos esos datos en memoria y que los combos de las distintas pestañas, independientemente de cuántas pestañas hubiera, se sirvieran de ellos. Como mucho, unos doscientos registros formados por dos campos: un valor numérico (clave primaria, a ligar al ValueMember) y una cadena de caracteres (el campo descriptor que se mostrará en el combo). Para trabajar con ello creé una clase muy sencilla que contuviera esos valores. En su forma más simple:<br />
</span></p>
<table border="0" width="90%" align="center" bgcolor="#e6e6fa">
<tbody>
<tr>
<td>
<pre style="font-family: 'Courier New', Courier, monospace; font-size:9pt"><span style="color:#0000FF">Public</span> <span style="color:#0000FF">Class</span> IdMasDescripcion
    <span style="color:#0000FF">Private</span> _Id <span style="color:#0000FF">As</span> <span style="color:#0000FF">Integer</span>
    <span style="color:#0000FF">Private</span> _Descripcion <span style="color:#0000FF">As</span> <span style="color:#0000FF">String</span>
    <span style="color:#0000FF">Public</span> <span style="color:#0000FF">Sub</span> <span style="color:#0000FF">New</span>(<span style="color:#0000FF">ByVal</span> Id <span style="color:#0000FF">As</span> <span style="color:#0000FF">Integer</span>, _
                   <span style="color:#0000FF">ByVal</span> Descripcion <span style="color:#0000FF">As</span> <span style="color:#0000FF">String</span>)
        _Id = Id
        _Descripcion = Descripcion
    <span style="color:#0000FF">End</span> <span style="color:#0000FF">Sub</span>
    <span style="color:#0000FF">Public</span> <span style="color:#0000FF">Sub</span> <span style="color:#0000FF">New</span>()

    <span style="color:#0000FF">End</span> <span style="color:#0000FF">Sub</span>
    <span style="color:#0000FF">Public</span> <span style="color:#0000FF">Property</span> Id() <span style="color:#0000FF">As</span> <span style="color:#0000FF">Integer</span>
        <span style="color:#0000FF">Get</span>
            <span style="color:#0000FF">Return</span> _Id
        <span style="color:#0000FF">End</span> <span style="color:#0000FF">Get</span>
        <span style="color:#0000FF">Set</span>(<span style="color:#0000FF">ByVal</span> <span style="color:#0000FF">value</span> <span style="color:#0000FF">As</span> <span style="color:#0000FF">Integer</span>)
            _Id = <span style="color:#0000FF">value</span>
        <span style="color:#0000FF">End</span> <span style="color:#0000FF">Set</span>
    <span style="color:#0000FF">End</span> <span style="color:#0000FF">Property</span>
    <span style="color:#0000FF">Public</span> <span style="color:#0000FF">Property</span> Descripcion() <span style="color:#0000FF">As</span> <span style="color:#0000FF">String</span>
        <span style="color:#0000FF">Get</span>
            <span style="color:#0000FF">Return</span> _Descripcion
        <span style="color:#0000FF">End</span> <span style="color:#0000FF">Get</span>
        <span style="color:#0000FF">Set</span>(<span style="color:#0000FF">ByVal</span> <span style="color:#0000FF">value</span> <span style="color:#0000FF">As</span> <span style="color:#0000FF">String</span>)
            _Descripcion = <span style="color:#0000FF">value</span>
        <span style="color:#0000FF">End</span> <span style="color:#0000FF">Set</span>
    <span style="color:#0000FF">End</span> <span style="color:#0000FF">Property</span>
<span style="color:#0000FF">End</span> <span style="color:#0000FF">Class</span></pre>
</td>
</tr>
</tbody>
</table>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Luego me declaré una serie de colecciones de IdMasDescripcion, digamos que unas List (of IdMasDescripcion). Al arrancar la aplicación y realizar la carga de datos, rellenos estas colecciones con los datos de las tablas respectivas. Luego, en el procedimiento que controla las pestañas, cuando se crea una, ligo cada colección a su ComboBox correspondiente (mediante su DataSource, etc.) y listo.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Bueno, listo, no. Ahora viene controlar que se muestren los datos actualizados en esos combos. Si, digamos, yo añado un nuevo tipo de archivo, la aplicación lo detecta y vuelve a rellenar la List(of T) correspondiente a esta tabla, los combos ya existentes no muestran los cambios. Oh, vaya.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">La solución es muy simple: la colección elegida no es la adecuada para esto. Si cambiamos la List(of T) por una BindingList(of T), problema solucionado.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">En resumen: vuelco los datos que necesito de una tabla de la base de datos a una BindingList. Enlazo todos los comboboxes que vayan a mostrar esos datos (uno por pestaña, vaya) a la BindingList y puedo mantenerlos todos actualizados para cuando vaya a modificar una release. Ahora que lo veo así, resulta evidente, pero en su momento me llevó bastante caer en ello.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">No me da tiempo a más. Si alguien quiere que ponga el código completo (aunque no es nada del otro mundo, la verdad), pues me lo pide y lo subo en cuanto pueda.<br />
</span></p>
<p style="text-align: justify"><span style="font-family:Verdana; font-size:10pt">Nos vemos en el <em>Forlon.</em></span></p>
]]></content:encoded>
			<wfw:commentRss>http://cromo.cda-ie.es/2009/07/02/mantener-actualizados-unos-combobox/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

