God is a DJ
Os iba a escribir un post sobre lo que hemos hecho hoy en clase, pero… que coño! hoy es viernes, así que os dejo un video que espero os guste tanto como a mí, que no sólo de código, pizzas y pornotube vive el programador.
Os iba a escribir un post sobre lo que hemos hecho hoy en clase, pero… que coño! hoy es viernes, así que os dejo un video que espero os guste tanto como a mí, que no sólo de código, pizzas y pornotube vive el programador.
En el curso, el otro día, quise poner el programa en el área de notificación, a la derecha de la barra de tareas de Windows, en tiempo de ejecución, usease, al lado del reloj de nuestro WindowsXP.
Para ello, tenemos que añadir al formulario el control NotifyIcon, que encontraremos dentro del Cuadro de Herramientas de VS2005, en Controles Comunes.
Una vez añadido, le ponemos que sea visible, le asignamos un icono (en mi caso una calavera ;) y le añado un texto que se mostrará cuando tenga el ratón encima. También le he añadido un ContextMenuStrip (ya hablaremos de él otro día) para que, cuando clickee encima, me salgan un menú con varias opciones, como podéis ver en las propiedades del control:
De esta forma, cuando ejecutemos el programa nos aparecerá lo siguiente (si ponemos el ratón encima aparecerá el texto que le hemos puesto):
Y nos queda la mar de chulo ;)
Como os decía ayer, estamos emulando un buscador de viajes de la web. Pues bien, como os imaginareis, tenemos un combo con el mes de salida, y cuando modificamos este, tenemos que modificar el combo del mes de llegada, poniendo el mismo mes que el de salida + 12.
Para ello, lo primero es activar el postback del combo del mes de salida:
![]() |
Una vez activado, programamos el evento SelectedIndexChanged del combo del mes de salida. Pero antes, un apunte, en el evento Page_Load de la página, cuando he cargado el combo, lo he hecho de la siguiente forma:
protected void AniadirMes()
{
DateTime Hoy;
for (int i = 0; i < 12; i++)
{
Hoy = DateTime.Now.AddMonths(i);
ListItem MiMes = new ListItem(Hoy.ToString("MMM yyyy"), Hoy.ToLongDateString());
//ddlMesLLegada.Items.Add(MiMes);
ddlMesSalida.Items.Add(MiMes);
}
}
De esta forma, en el value del combo me guardo la fecha, así cuando llamo al evento SelectedIndexChanged del mismo, tengo la fecha seleccionada en el value, así no me como la cabeza para saber de que mes estoy hablando ;).
Como ibamos, una vez que modifiquemos el combo, saltará dicho evento, en el cual tengo lo siguiente:
ddlMesLLegada.Enabled = true;
ddlMesLLegada.Items.Clear();
DateTime Salida = DateTime.Parse(ddlMesSalida.SelectedValue);
DateTime Hoy;
for (int i = 0; i < 12; i++)
{
Hoy = Salida.AddMonths(i);
ListItem MiLista = new ListItem(Hoy.ToString("MMM yyyy"), Hoy.ToLongDateString());
ddlMesLLegada.Items.Add(MiLista);
}
Y de esta forma cargo el segundo combo a partir del primer combo.
En el curso, estamos emulando una pagina web de vuelos de bajo coste de cara a aprender un poco de diseño (uso masivo de div y css en detrimento de las tablas) y empezar a utilizar las herramientas propias de ASP.NET. estamos emulando sólo la parte de la izquierda, la de la busqueda de vuelos.
Pues bien, en la página hemos introducido un DropDownList donde metemos las ciudades origen de los vuelos. Este DropDownList lo cargamos con los datos que hay en una tabla. Pero claro, en vez de que aparezca la primera ciudad de la tabla, queremos que aparezca la palabra Origen como primer elemento del DropDownList. para ello utilizaremos el siguiente código:
DropDownList1.Items.Insert(0, new ListItem("Origen", "0"));
Donde le indicamos, primero, el lugar que ocupara (el 0, para que sea el primero) y luego le metemos el texto y el valor que tendrá con un ListItem.
En el curso me he visto en la necesidad de abrir un formulario, y que este quede en medio de otro formulario. Hay dos formas de hacerlo, aunque esto depende de la forma en que abramos el formulario, es decir, si lo hacemos de forma modal o no.
Si lo hacemos de forma modal, el formulario tiene una propiedad llamada .StartPosition a la cual le pondremos el valor FormStartPosition.CenterParent, que, traducido del marciano, viene a decir, que la posición inicial del formulario es en el centro del formulario padre. Si en vez de por diseño, utilizando la ventana de propiedades que nos proporciona el VS2005, se lo metemos por código (dentro del constructor lo he metido yo), sería tal que asin:
this.StartPosition = FormStartPosition.CenterParent;
Eso si, cuando llamemos al método .ShowDialog() del formulario, deberemos usar el metodo sobrecargado en el que le indiquemos quien es su padre:
MiFormulario.ShowDialog(this);
Ahora bien, si no lo abrimos de forma modal, utilizaremos el método .Show() y ya entonces estaremos en la necesidad de utilizar el .Location del formulario, ya que el this.StartPosition = FormStartPosition.CenterParent; sólo funciona con los modales. Para ello debemos calcular la posición que va ha tener el nuevo formulario asignándolo a una variable de tipo Point, el cual representa un par ordenado de coordenadas x e y de enteros que define un punto en el plano bidimensional, usease, lo que contiene el .Location del formulario.
//El this es el formulario padre
//el PeqForm el formulario hijo
Int32 X1 = this.Location.X + (this.Width / 2) - (PeqForm.Width / 2);
Int32 Y1 = this.Location.Y + (this.Height / 2) - (PeqForm.Height / 2);
Point P = new Point(X1, Y1);
Ahora ya sólo queda meterle al nuevo formulario los nuevos datos en el .Location, pero, eso sí, hay que meterselo despues de lanzar el .Show(), ya que, sino, no le hace ni puñetero caso:
PeqForm.Show();
PeqForm.Location = P;
PeqForm.Refresh();
Y despues refrescamos el formulario para ver los cambios realizados ;)
En el curso, estamos haciendo una aplicación en la que guardamos los datos en un fichero XML (sí, para guardar datos mejor utilizar el SQLServer o análogos, pero el objetivo no es la aplicación en sí, sino aprender a escribir y leer archivos XML desde C#).
La forma de guardar archivos XML con el formato que queremos es el siguiente, aunque, antes de empezar, un pequeño apunte: La estructura de un archivo XML es jerárquica, en forma de arbol, y, como prerequisito, un archivo XML sólo puede contener un nodo padre, en el cual estarán todos los nodos hijos que queramos. Una vez aclarado esto, sigamos.
El código que vereís un poco más abajo tiene como objetivo crear un archivo XML que sea tal que asi:
<XClub>
<Pelicula>
<Data Titulo="Garganta Profunda(Deep Throat)" Director="Gerard Damiano" />
</Pelicula>
</XClub>
Pues bien, aquí teneis el código en C# que crea el documento XML que queremos:
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
System.Xml.XmlNode XClub = doc.CreateElement("XClub");
doc.AppendChild(XClub);
System.Xml.XmlNode Pelicula = doc.CreateElement("Pelicula");
XClub.AppendChild(Pelicula);
System.Xml.XmlNode Data = doc.CreateElement("Data");
System.Xml.XmlAttribute atributo = doc.CreateAttribute("Titulo");
atributo.InnerText = "Garganta Profunda(Deep Throat)";
Data.Attributes.Append(atributo);
System.Xml.XmlAttribute atributo2 = doc.CreateAttribute("Director");
atributo2.InnerText = "";
Data.Attributes.Append(atributo2);
Pelicula.AppendChild(Data);
doc.Save(pRutaGuardarXML);
Si os fijais, aunque he ido creando los nodos y atributos del XML de forma ordenada, la creación de estos es independiente al diseño, es decir, si quisiese hubiese podido, primero, crearme todos los nodos y atributos del XML y, despues, decir quien pertenece a quien, por lo que el código quedaría de la siguiente forma:
//Me creo los nodos y los atributos
System.Xml.XmlDocument doc = new
System.Xml.XmlDocument();
System.Xml.XmlNode XClub = doc.CreateElement("XClub");
System.Xml.XmlNode Pelicula = doc.CreateElement("Pelicula");
System.Xml.XmlNode Data = doc.CreateElement("Data");
System.Xml.XmlAttribute atributo = doc.CreateAttribute("Titulo");
atributo.InnerText = "Garganta Profunda(Deep Throat)";
System.Xml.XmlAttribute atributo2 = doc.CreateAttribute("Director");
atributo2.InnerText = "Gerard Damiano";
//Y ahora los ordeno como me salga de los webs
doc.AppendChild(XClub);
XClub.AppendChild(Pelicula);
Data.Attributes.Append(atributo);
Data.Attributes.Append(atributo2);
Pelicula.AppendChild(Data);
doc.Save(pRutaGuardarXML);
Es decir, la creación de los elementos es independiente a como vayamos a estructurar el archivo XML (aunque para una claridad mayor y por razones lógicas, lo hagamos de una forma ordenada, sobretodo, si creamos los nodos a partir de colecciones, arrays, listas o lo que hallamos utilizado, recorriendo dichos objetos con un foreach), por lo que ambos ejemplos de código generaran el mismo archivo XML.
Cualquier duda, pregunta, corrección (que naide es perfesto), crítica, bug… en los comentarios ;)
Jejejeje, si ayer me comía la cabeza para saber como coger el nombre de un fichero dada su ruta, hoy es al reves, quiero conocer el directorio en el que está, quiero la ruta del directorio. esta vez no he empezado a hacer substring ni nada por el estilo, sino que me he ido directamente a System.IO.Path y he encontrado el método .GetDirectoryName(string Ruta).
Funciona igual que el .GetFileName (string ruta), pero al contrario de esta, te da la ruta del directorio, no el nombre del fichero:
Directorio = System.IO.Path.GetDirectoryName(mRutaCartel);
Otro truco más pal body ;)
Hoy me estaba comiendo la cabeza en el curso. ¿La causa? Tengo en una lista una ruta de una imagen, y necesitaba coger el nombre del fichero, no la ruta entera, para almacenarla en un XML. Pues bien, me estaba liando a crearme un array de string de la ruta con el método .Split() y asumir que el último elemento del array era el nombre del fichero, pero como Iñaki aka el otro profe indica, ya hay muchas cosicas que el framework tiene ya hechas y esta es una de ellas. Dentro de System.IO.Path hay un método público llamado .GetFileName(string RutaFichero) que te devuelve exactamente eso, el nombre del fichero dada una ruta completa:
FileCartel = System.IO.Path.GetFileName(mRutaCartel);
Ya veis, más que comerse el tarro en como hacerlo, hay que comerselo en buscarlo dentro del framework ;)
En una aplicación que estamos realizando en el curso (que ya os la pondré cuando la tengamos terminada), me he visto en la necesidad de concatenar varios campos string. Como me acordé del artículo que escribio Jorge Serrano en geek.ms titulado Rendimiento iterando cadenas, de lectura muy recomendada, he utilizado la clase StringBuilder (para saber el porqué, leeros el artículo que os he comentado).
La utilización de esta clase es muy simple y facil como vereis en el siguiente ejemplo:
Primero me declaro un array de tipo string de 5 elementos donde guardo el nombre de 5 paises:
string[] Paises = new string[5];
Paises[0] = “Chile”;
Paises[1] = “Argentina”;
Paises[2] = “Brasil”;
Paises[3] = “Uruguay”;
Paises[4] = “Paraguay”;
Y a continuación meto estos 5 países en un RichTextBox utilizando la clase StringBuilder:
StringBuilder Pais = new StringBuilder();
foreach (string MiPais in Paises)
{
Pais.Append(MiPais + "\n");
}
richTextBox1.Text = Pais.ToString();
Para ello, primero me declaro una variable de tipo StringBuilder y la inicializo. Me recorro el array Paises con un foreach y voy añadiendo a la variable de tipo StringBuilder Pais, utilizando el método .Append, el contenido del array. Para finalizar lo meto en el .Text del richTextBox, para lo cual convierto el StringBuilder a string con el método .ToString(), ya que si no peta la aplicación.
Ala, que ya es viernes, que paseis buen finde!
Ayer hicimos un programica que nos hacía una copia de un directorio en el directorio que nosotros le indicasemos, usease, una especie de copia de seguridad de nuestros archivos. La solución que encontré yo, fue hacer una función recursiva de cara a recorrerme todos los directorios.
Creo que existe, por lo menos en VB.NET, la opción de copiar una carpeta y su contenido en otra carpeta, pero el ejercicio consistía en ir archivo a archivo y controlar si había errores al copiarlos, generando un log. En este caso lo que utilizo para crear el log es una cola genérica tipada como string (System.Collections.Generic.Queue<string>) donde guardo los mensajes de error para jugar luego con ellos como mejor me plazca:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | private void MoverArchivos1(string Destino, string Origen) { FileInfo[] MisFiles; DirectoryInfo[] MisDir; int ContadorDir = 0; MisFiles = new DirectoryInfo(Origen).GetFiles(); MisDir = new DirectoryInfo(Origen).GetDirectories(); ContadorDir = MisDir.GetLength(0); foreach (FileInfo Archivo in MisFiles) { try { Archivo.CopyTo(Destino + "\\" + Archivo.Name); } catch (Exception e) { MiFiFo.Enqueue("FAILURE: " + Destino + "\\" + Archivo.Name + "\r" + e.Message + "\r"); } } for (int i = 0; i < ContadorDir; i++) { CrearDirectorio(Destino + "\\" + MisDir[i].Name); MoverArchivos1(Destino + "\\" + MisDir[i].Name, MisDir[i].FullName); } } |
Otra forma de hacerlo, que es la que aporto Rafa aka El Profe, esta vez sin ser recursivo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | private void MoverArchivos2(string Destino, string Origen) { DirectoryInfo di; di = new DirectoryInfo(Origen); FileInfo[] fis; fis = di.GetFiles("*.*", SearchOption.AllDirectories); foreach (FileInfo Fi in fis) { string s; s = Fi.FullName.Replace(Origen, Destino); FileInfo Fid; Fid = new FileInfo(s); if (!Directory.Exists(Fid.DirectoryName)) Directory.CreateDirectory(Fid.DirectoryName); try { Fi.CopyTo(s, true); } catch (IOException ex) { MiFiFo.Enqueue("FAILURE: " + Destino + "\\" + Fi.Name + "\r" + ex.Message + "\r"); } } } |
El Destino y Origen son las rutas de los directorios, que las he guardado en un app.config, y por otro lado, valido que la ruta destino exista y este vacia.
Dudas? Preguntas? Bugs? Que solución os gusta más?