- Introducción
Como la mayoría sabréis, SQLite es un sistema de gestión de bases de datos relaciones, que tiene la particularidad de que no necesita ningún tipo de instalación ni configuración en el sistema donde se ejecuta. Está todo contenido en una pequeña librería.
Es ideal si necesitas que tu programa maneje una pequeña base de datos, pero no quieres (o no puedes) andar instalando o configurando los equipos donde se va a ejecutar.
En este artículo explicaré en cuatro pasos cómo usar SQLite en un programa C#, usando Visual Studio 2010.
- Instalación.
No necesitas instalar nada en la máquina de desarrollo. Sólo tienes que ir a esta página:
http://system.data.sqlite.org/index.html/doc/trunk/www/downloads.wiki
Hay dos tipos de paquetes: fuentes y binarios precompilados. Necesitas descargar el paquete binario adecuado para el sistema donde tu programa va a correr (no donde estás desarrollando). Por ejemplo, si tu programa usará .Net 4.0 en una plataforma Win 32, deberías descargar sqlite-netFx40-binary-bundle-Win32-2010-1.0.88.0
Dentro del fichero verás que vienen varios ejecutables y DLLs. Sólo vas a necesitar la librería System.Data.SQLite.dll, y System.Data.SQLite.Linq.dll si además usas Linq.
Lo más sencillo es crear una carpeta llamada "Externals" o "Librerías" dentro de tu proyecto, y copiar ahí la(s) DLL(s) que necesites. Después, añade una referencia en tu proyecto a la DLL.
En la siguiente imagen puedes ver cómo queda tu proyecto, con el fichero y la referencia al fichero resaltados en amarillo:
- Uso
Ya puedes usar SQLite desde tu programa. Tras añadir la instrucción "using":
using System.Data.SQLite;
... puedes usar las clases de toda la vida. Empezaríamos con:
SQLiteConnection con = new SQLiteConnection("Data Source=prueba.db");
con.Open();
para abrir o crear (si no existe) una base de datos. Para crear una tabla:
SQLiteCommand cmd = new SQLiteCommand();
cmd.Connection = con;
cmd.CommandText = "create table if not exists productos (referencia text, descripcion text, precio real)";
cmd.ExecuteNonQuery();
para introducir datos:
cmd.CommandText = "insert into productos (referencia, descripcion, precio) values ('ref1', 'descripción 1', 10.0) ";
cmd.ExecuteNonQuery();
cmd.CommandText = "insert into productos (referencia, descripcion, precio) values ('ref2', 'descripción 2', 20.0) ";
cmd.ExecuteNonQuery();
Para leer datos ....
cmd.CommandText = "select * from productos";
SQLiteDataReader dr = cmd.ExecuteReader();
StringBuilder sb = new StringBuilder();
while (dr.Read())
{
sb.AppendLine(dr[0].ToString() + " " + dr[1].ToString() + " " + dr[2].ToString());
}
MessageBox.Show(sb.ToString(), "yuju", MessageBoxButton.OK, MessageBoxImage.Information);
En fin, estoy convencido de que coges la idea :) Si quieres, aquí tienes el manual de referencia de la variante de SQL que usa SQLite.
Mostrando entradas con la etiqueta C#. Mostrar todas las entradas
Mostrando entradas con la etiqueta C#. Mostrar todas las entradas
martes, 8 de octubre de 2013
jueves, 11 de abril de 2013
Accediendo a los números de versión ClickOnce desde C#
Más que una entrada de blog, es una nota para mi mismo. Para acceder a los números de versión ClickOnce :
a- Añadir una referencia a System.Deployment en el proyecto.
b- Añadir directiva
using System.Deployment.Application;
c- Antes de acceder a los números de versión, debemos comprobar si la aplicación está corriendo en una instalación, o si estamos dentro de Visual Studio. Si queremos mostrar la información en la barra del título de nuestro formulario:
if (ApplicationDeployment.IsNetworkDeployed)
this.Title += " v. " + ApplicationDeployment.CurrentDeployment.CurrentVersion.Major + "." + ApplicationDeployment.CurrentDeployment.CurrentVersion.Minor;
else
this.Title += " (entorno desarrollo) ";
a- Añadir una referencia a System.Deployment en el proyecto.
b- Añadir directiva
using System.Deployment.Application;
c- Antes de acceder a los números de versión, debemos comprobar si la aplicación está corriendo en una instalación, o si estamos dentro de Visual Studio. Si queremos mostrar la información en la barra del título de nuestro formulario:
if (ApplicationDeployment.IsNetworkDeployed)
this.Title += " v. " + ApplicationDeployment.CurrentDeployment.CurrentVersion.Major + "." + ApplicationDeployment.CurrentDeployment.CurrentVersion.Minor;
else
this.Title += " (entorno desarrollo) ";
jueves, 22 de marzo de 2012
Sirviendo actualizaciones ClickOnce desde un servidor Apache.
Como programador, estoy encantado con el sistema "ClickOnce" de actualización de Microsoft. Permite instalar y distribuir actualizaciones de forma práctica y rápida.
Como administrador de sistemas, soy un firme partidario del servidor web Apache, por razones técnicas, económicas (sin coste de licencias) y prácticas (es el servidor web más utilizado en Internet).
Pero independientemente de las opiniones de cada uno, a veces hay que hacer funcionar ClickOnce sobre Apache, y punto pelota :) Veamos como.
Lo primero, aclarar que sólo he conseguido que funcione para actualizar, no para instalar por primera vez el programa. Por eso el artículo se llama "sirviendo actualizaciones". Yo suelo hacer la instalación manualmente en los equipos de los clientes, y luego utilizo Apache para distribuir las actualizaciones, que suele ser el 90% del trabajo.
En primer lugar, hay que preparar el alojamiento web para nuestros ficheros. Puedes hacerlo mediante un host virtual, a través de un puerto diferente o de un subdirectorio dentro de tu sitio web. En mi caso, utilizo un subdirectorio, por lo que los ficheros son accesibles desde:
http://www.miweb.com/aplicacion
Mientras preparas el alojamiento, ten en cuenta las restricciones de seguridad que quieras aplicar. Creo que es aconsejable, al menos, limitar las IPs desde las que se pueden conectar a las IPs del cliente. En fin, haz lo que quieras. En el manual de Apache viene todo muy bien explicadito :)
En segundo lugar, hay que preparar la aplicación para que se actualice a través de web.
En Visual Studio 2010, saca las propiedades de tu proyecto y vete a la solapa de Publicar. En la casilla Ubicación de la carpeta de publicación debes poner una carpeta de tu ordenador, por ejemplo "C:\publicaciones".
En el botón de Actualizaciones, selecciona "la aplicación debe buscar actualizaciones", y en la "Ubicación de actualizaciones" pon el alojamiento que preparaste en el primer paso. En mi caso, http://www.miweb.com/aplicacion El resto de parámetros ponlos como quieras. Yo prefiero que las actualizaciones se busquen antes de ejecutar la aplicación, pero eso ya es cosa de cada uno.
Finalmente, quedan los pasos que hay que seguir cada vez que quieras liberar una actualización.
En primer lugar, evidentemente, debes generar los ficheros de publicación. En las propiedades del proyecto, selecciona "Publicar ahora". En nuestro ejemplo, eso generará los ficheros de actualización en la carpeta C:\publicaciones
Copia todo el contenido de "C:\publicaciones" a tu alojamiento web (probablemente algo como /var/www/miweb/aplicacion o /home/usuario/public_html/aplicacion).
Ahora, debes asegurarte de que todos los ficheros tienen activado el permiso +r para todos los usuarios. Si puedes conectarte por SSH, la orden es:
find . -exec chmod ugo+r \{\} \;
Si no puedes conectarte por SSH, usa tu cliente de FTP para cambiar los permisos.
Finalmente, debes activar el permiso +x a todos los directorios. Por SSH, se haría:
find . -type d -exec chmod ugo+x \{\} \;
o usa tu cliente FTP.
Debes cambiar los permisos cada vez que subas una actualización, o lo más probable es que los clientes no se actualicen.
Pues eso es todo. Happy ClickOnce.
Como administrador de sistemas, soy un firme partidario del servidor web Apache, por razones técnicas, económicas (sin coste de licencias) y prácticas (es el servidor web más utilizado en Internet).
Pero independientemente de las opiniones de cada uno, a veces hay que hacer funcionar ClickOnce sobre Apache, y punto pelota :) Veamos como.
Lo primero, aclarar que sólo he conseguido que funcione para actualizar, no para instalar por primera vez el programa. Por eso el artículo se llama "sirviendo actualizaciones". Yo suelo hacer la instalación manualmente en los equipos de los clientes, y luego utilizo Apache para distribuir las actualizaciones, que suele ser el 90% del trabajo.
En primer lugar, hay que preparar el alojamiento web para nuestros ficheros. Puedes hacerlo mediante un host virtual, a través de un puerto diferente o de un subdirectorio dentro de tu sitio web. En mi caso, utilizo un subdirectorio, por lo que los ficheros son accesibles desde:
http://www.miweb.com/aplicacion
Mientras preparas el alojamiento, ten en cuenta las restricciones de seguridad que quieras aplicar. Creo que es aconsejable, al menos, limitar las IPs desde las que se pueden conectar a las IPs del cliente. En fin, haz lo que quieras. En el manual de Apache viene todo muy bien explicadito :)
En segundo lugar, hay que preparar la aplicación para que se actualice a través de web.
En Visual Studio 2010, saca las propiedades de tu proyecto y vete a la solapa de Publicar. En la casilla Ubicación de la carpeta de publicación debes poner una carpeta de tu ordenador, por ejemplo "C:\publicaciones".
En el botón de Actualizaciones, selecciona "la aplicación debe buscar actualizaciones", y en la "Ubicación de actualizaciones" pon el alojamiento que preparaste en el primer paso. En mi caso, http://www.miweb.com/aplicacion El resto de parámetros ponlos como quieras. Yo prefiero que las actualizaciones se busquen antes de ejecutar la aplicación, pero eso ya es cosa de cada uno.
Finalmente, quedan los pasos que hay que seguir cada vez que quieras liberar una actualización.
En primer lugar, evidentemente, debes generar los ficheros de publicación. En las propiedades del proyecto, selecciona "Publicar ahora". En nuestro ejemplo, eso generará los ficheros de actualización en la carpeta C:\publicaciones
Copia todo el contenido de "C:\publicaciones" a tu alojamiento web (probablemente algo como /var/www/miweb/aplicacion o /home/usuario/public_html/aplicacion).
Ahora, debes asegurarte de que todos los ficheros tienen activado el permiso +r para todos los usuarios. Si puedes conectarte por SSH, la orden es:
find . -exec chmod ugo+r \{\} \;
Si no puedes conectarte por SSH, usa tu cliente de FTP para cambiar los permisos.
Finalmente, debes activar el permiso +x a todos los directorios. Por SSH, se haría:
find . -type d -exec chmod ugo+x \{\} \;
o usa tu cliente FTP.
Debes cambiar los permisos cada vez que subas una actualización, o lo más probable es que los clientes no se actualicen.
Pues eso es todo. Happy ClickOnce.
viernes, 18 de noviembre de 2011
C#: Ficheros y rutas de trabajo temporales en Windows.
Ésto lo escribo más como un recordatorio para mi mismo que otra cosa.
Para obtener el directorio de trabajo temporal en Windows, puede usarse la siguiente función:
Path.GetTempPath()
Esta función crea un fichero vacío con un nombre único , y te devuelve su nombre:
Path.GetTempFileName()
Para obtener el directorio de trabajo temporal en Windows, puede usarse la siguiente función:
Path.GetTempPath()
Esta función crea un fichero vacío con un nombre único , y te devuelve su nombre:
Path.GetTempFileName()
viernes, 11 de febrero de 2011
C#: Acceso directo a ficheros de Word 2010
- Introducción.
A veces es útil acceder directamente a un fichero de Word en formato .docx desde un programa en C#. Por ejemplo, yo lo uso para generar documentos personalizados más allá de lo que permite la opción "combinar correspondencia", insertar imágenes, etc.
Antes, los ficheros de word eran binarios y esas tareas había que hacerlas a través de la aplicación Word con objetos COM. Desde la introducción del formato open XML (.docx), el mundo es un lugar mejor para los programadores.
- El meollo de la cuestión.
Un fichero .docx no es más que un fichero comprimido .zip , que contiene todos los ficheros e imágenes del documento de Word en formato XML.
Si quieres hacer la prueba, crea un fichero prueba.docx, escribe algo de texto, inserta una imagen, guárdalo, sal de Word, renómbralo como prueba.xml, y ábrelo. Verás un fichero XML, y varias carpetas. Entra en la carpeta "word", y abre el fichero "document.xml" Ahí está tu texto. Si abres la carpeta "media", verás tus imágenes.
Finalmente, cierra los ficheros, y renombra la carpeta prueba.zip por prueba.docx Podrás abrirlo sin problema con word.
En los siguientes apartados veremos cómo modificar el fichero a través de C# Voy a usar las siguientes variables:
string directorio_trabajo = Path.GetTempPath();
string fichero_entrada ="prueba";
string fichero_salida = "prueba2.docx";
... donde, evidentemente, directorio_trabajo es un directorio temporal donde comprimir/descomprimir los ficheros, fichero_entrada es el fichero "plantilla" que nos va a servir de base para generar la documentación, y fichero_salida va a contener el resultado.
En los ejemplos de código siguientes, vamos a suponer que fichero_entrada se encuentra dentro del directorio_trabajo.
- Descomprimiendo el fichero.
Hace años, cuando investigué la forma de acceder a ficheros OpenXML, C# no tenía forma de acceder a una carpeta ZIP. La solución que encontré (no muy elegante), es usar un programa externo para comprimir y descomprimir los ficheros. Busca (en Google) una versión libre de zip.exe y unzip.exe como esta....
http://stahlworks.com/dev/index.php?tool=zipunzip
Una vez tengas esos ejecutables, añádelos a tu proyecto, y usa este código para llamarlo:
string orden = "\"" + Application.StartupPath + "\\unzip.exe\"";
string parametros = "\"" + Application.StartupPath + "\\prueba.docx\"";
System.Diagnostics.Process p = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo(orden);
info.UseShellExecute = true;
info.Arguments = parametros;
info.WorkingDirectory = dir_trabajo;
info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
p.StartInfo = info;
while (!p.Start()) ;
while (!p.HasExited) ;
Dependiendo de dónde esté tu fichero docx, tendrás que ajustar un poco las rutas de los ficheros en tu código.
- Cambiando el texto del fichero.
Dentro del árbol de ficheros que aparece tras descomprimir el .docx, debes abrir el fichero \word\document.xml.
La forma elegante de hacer los cambios es cargar el fichero XML con la clase XmlDocument , buscar los nodos que contienen el texto que quieres sustituir y volver a crear el fichero. Desgraciadamente, me pagan por programar rápido y no por programar elegantemente :)
La forma más rápida de hacer cambios es cargar el fichero XML en una cadena de texto:
// Leemos toda la cadena en un fichero.
string documento = File.ReadAllText(fichero + "\\word\\document.xml");
// Pon aquí los cambios que necesites. En el ejemplo, sustituyo la cadena "{nombre}" en
// la plantilla por un nombre cualquiera.
documento = documento.Replace("{nombre}", "Armando Bronca Segura");
// Volvemos a grabar el fichero.
File.WriteAllText(fichero + "\\word\\document.xml", documento);
- Cambiando imágenes.
La forma más sencilla de cambiar imágenes en un documento es insertar una imagen desde Word en la plantilla, y luego sustituirla por otra en tu programa.
Las imágenes están en la carpeta \word\media\image1.gif , \word\media\image2.gif ... Antes de de escribir el programa, debes ver qué nombre le ha dado Word a tu imagen, para poder sustituirla por otra.
Si tienes un fichero con la nueva imagen, solo tienes que copiarlo usando la librería IO:
File.Copy ("mi_imagen.gif", @" \word\media\image2.gif");
Si quieres copiar el contenido del portapapeles como una imagen, usa este código:
if (Clipboard.GetDataObject() != null)
{
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.Bitmap))
{
Image image = (Image)data.GetData(DataFormats.Bitmap, true);
image.Save(Directory.GetCurrentDirectory() + "\\" + fichero + "\\word\\media\\image1.gif", System.Drawing.Imaging.ImageFormat.Gif);
}
}
- Comprimiendo el fichero.
Una vez hechos todos los cambios, hay que volver a crear el documento .docx
string orden = "\"" + Application.StartupPath + "\\zip.exe\"";
string parametros = " -r -9 \"" + dir_salida + @"\prueba2.docx\" *";
System.Diagnostics.Process p = new System.Diagnostics.Process();
A veces es útil acceder directamente a un fichero de Word en formato .docx desde un programa en C#. Por ejemplo, yo lo uso para generar documentos personalizados más allá de lo que permite la opción "combinar correspondencia", insertar imágenes, etc.
Antes, los ficheros de word eran binarios y esas tareas había que hacerlas a través de la aplicación Word con objetos COM. Desde la introducción del formato open XML (.docx), el mundo es un lugar mejor para los programadores.
- El meollo de la cuestión.
Un fichero .docx no es más que un fichero comprimido .zip , que contiene todos los ficheros e imágenes del documento de Word en formato XML.
Si quieres hacer la prueba, crea un fichero prueba.docx, escribe algo de texto, inserta una imagen, guárdalo, sal de Word, renómbralo como prueba.xml, y ábrelo. Verás un fichero XML, y varias carpetas. Entra en la carpeta "word", y abre el fichero "document.xml" Ahí está tu texto. Si abres la carpeta "media", verás tus imágenes.
Finalmente, cierra los ficheros, y renombra la carpeta prueba.zip por prueba.docx Podrás abrirlo sin problema con word.
En los siguientes apartados veremos cómo modificar el fichero a través de C# Voy a usar las siguientes variables:
string directorio_trabajo = Path.GetTempPath();
string fichero_entrada ="prueba";
string fichero_salida = "prueba2.docx";
... donde, evidentemente, directorio_trabajo es un directorio temporal donde comprimir/descomprimir los ficheros, fichero_entrada es el fichero "plantilla" que nos va a servir de base para generar la documentación, y fichero_salida va a contener el resultado.
En los ejemplos de código siguientes, vamos a suponer que fichero_entrada se encuentra dentro del directorio_trabajo.
- Descomprimiendo el fichero.
Hace años, cuando investigué la forma de acceder a ficheros OpenXML, C# no tenía forma de acceder a una carpeta ZIP. La solución que encontré (no muy elegante), es usar un programa externo para comprimir y descomprimir los ficheros. Busca (en Google) una versión libre de zip.exe y unzip.exe como esta....
http://stahlworks.com/dev/index.php?tool=zipunzip
Una vez tengas esos ejecutables, añádelos a tu proyecto, y usa este código para llamarlo:
string orden = "\"" + Application.StartupPath + "\\unzip.exe\"";
string parametros = "\"" + Application.StartupPath + "\\prueba.docx\"";
System.Diagnostics.Process p = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo(orden);
info.UseShellExecute = true;
info.Arguments = parametros;
info.WorkingDirectory = dir_trabajo;
info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
p.StartInfo = info;
while (!p.Start()) ;
while (!p.HasExited) ;
Dependiendo de dónde esté tu fichero docx, tendrás que ajustar un poco las rutas de los ficheros en tu código.
- Cambiando el texto del fichero.
Dentro del árbol de ficheros que aparece tras descomprimir el .docx, debes abrir el fichero \word\document.xml.
La forma elegante de hacer los cambios es cargar el fichero XML con la clase XmlDocument , buscar los nodos que contienen el texto que quieres sustituir y volver a crear el fichero. Desgraciadamente, me pagan por programar rápido y no por programar elegantemente :)
La forma más rápida de hacer cambios es cargar el fichero XML en una cadena de texto:
// Leemos toda la cadena en un fichero.
string documento = File.ReadAllText(fichero + "\\word\\document.xml");
// Pon aquí los cambios que necesites. En el ejemplo, sustituyo la cadena "{nombre}" en
// la plantilla por un nombre cualquiera.
documento = documento.Replace("{nombre}", "Armando Bronca Segura");
// Volvemos a grabar el fichero.
File.WriteAllText(fichero + "\\word\\document.xml", documento);
- Cambiando imágenes.
La forma más sencilla de cambiar imágenes en un documento es insertar una imagen desde Word en la plantilla, y luego sustituirla por otra en tu programa.
Las imágenes están en la carpeta \word\media\image1.gif , \word\media\image2.gif ... Antes de de escribir el programa, debes ver qué nombre le ha dado Word a tu imagen, para poder sustituirla por otra.
Si tienes un fichero con la nueva imagen, solo tienes que copiarlo usando la librería IO:
File.Copy ("mi_imagen.gif", @" \word\media\image2.gif");
Si quieres copiar el contenido del portapapeles como una imagen, usa este código:
if (Clipboard.GetDataObject() != null)
{
IDataObject data = Clipboard.GetDataObject();
if (data.GetDataPresent(DataFormats.Bitmap))
{
Image image = (Image)data.GetData(DataFormats.Bitmap, true);
image.Save(Directory.GetCurrentDirectory() + "\\" + fichero + "\\word\\media\\image1.gif", System.Drawing.Imaging.ImageFormat.Gif);
}
}
- Comprimiendo el fichero.
Una vez hechos todos los cambios, hay que volver a crear el documento .docx
string orden = "\"" + Application.StartupPath + "\\zip.exe\"";
string parametros = " -r -9 \"" + dir_salida + @"\prueba2.docx\" *";
System.Diagnostics.Process p = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo(orden);
info.UseShellExecute = true;
info.Arguments = parametros;
info.WorkingDirectory = dir_trabajo;
info.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
p.StartInfo = info;
while (!p.Start()) ;
while (!p.HasExited) ;
- Abriendo el fichero.
Probablemente querrás abrir el fichero con Word desde tu aplicación para que el usuario no tenga que buscarlo y abrirlo él.
System.Diagnostics.Process p = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo(plantilla);
info.UseShellExecute = true;
p.StartInfo = info;
while(!p.Start());
Saludos :)
miércoles, 9 de febrero de 2011
C#: Tareas multihilo en dos patás.
- Introducción.
Como probablemente ya sabes, hoy en día es importante construir tus aplicaciones de forma que aprovechen los múltiples "cores" de los procesadores y que sean capaces de seguir respondiendo al usuario aunque "por detrás" estén ejecutando procesos pesados.
En los viejos tiempos (más o menos, a principios del año pasado) , los programadores de C# usábamos el objeto BackgroundWorker para construir aplicaciones multihilo. Con la llegada de .NET 4, tenemos una nueva herramienta: los objetos Task.
A continuación encontrarás algunos fragmentos de código útiles para crear tareas y organizar su ejecución. Dejo de lado el tratamiento de excepciones y el paso de parámetros para otro artículo.
- Para crear una tarea.
Imagínate que tienes un formulario, y que quieres ejecutar una tarea cuando se carga (por ejemplo, leer unos datos de la base de datos).
using System.Threading.Tasks;
....
private void Callejero_Load(object sender, EventArgs e)
{
Task t1 = new Task(
() =>
{
// Cargamos la lista de provincias en el control.
});
t1.Start();
}
Este método, define una tarea, solicita que se empiece a ejecutar, y sale sin esperar a que termine. El formulario seguirá respondiendo al usuario mientras ejecuta otras tareas en segundo plano.
Una cosa importante es que no puedes acceder a los controles del formulario desde un hilo distinto al que lo ha creado. Por ejemplo, la tarea no podrá cambiar el valor de una caja de texto del formulario directamente. Más adelante veremos un ejemplo de cómo hacerlo.
- Definir una tarea que se ejecute cuando otra termine.
Si tenemos una tarea T1 (como la anterior), y queremos definir una tarea T2 que se ejecute a continuación...
Task t2 = t1.ContinueWith(
ant =>
{
// Hacer más cosas
});
No es necesario llamar a Start() en una tarea de continuación (de hecho da un error). La tarea se arrancará automáticamente cuando T1 termine.
- Definir una tarea que se ejecute cuando varias tareas terminen.
Si tenemos dos tareas T1 y T2 que se van a ejecutar en paralelo, y queremos definir una tarea T3 que arranque cuando las otras dos terminen ...
Task t3 = Task.Factory.ContinueWhenAll(
new[] { t1, t2 },
tasks =>
{
// Hacemos más cosas
}
);
- Definir una tarea que se ejecute cuando otra termina, y actualice controles de nuestro formulario WPF.
Este es un caso muy típico. Imagínate que tienes un formulario que, cuando pulsas un botón, arranca una tarea T1. Cuando la tarea empieza, apagas un botón para que el usuario no le vuelva a dar. Cuando la tarea termina, quieres volver a habilitarlo. Nada más fácil.
Task t_final = t_1.ContinueWith(
ant =>
{
btn_procesar.IsEnabled = true;
}, TaskScheduler.FromCurrentSynchronizationContext());
- Definir una tarea que se ejecute cuando terminan otras, y actualice controles de nuestro formulario.
Task tarea_final = Task.Factory.ContinueWhenAll(
new[] { task_eventos, task_estados, task_info, task_parametros, task_control, task_canont },
tasks =>
{
// Accedemos a controles de nuestro formulario.
},
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext()
);
Como probablemente ya sabes, hoy en día es importante construir tus aplicaciones de forma que aprovechen los múltiples "cores" de los procesadores y que sean capaces de seguir respondiendo al usuario aunque "por detrás" estén ejecutando procesos pesados.
En los viejos tiempos (más o menos, a principios del año pasado) , los programadores de C# usábamos el objeto BackgroundWorker para construir aplicaciones multihilo. Con la llegada de .NET 4, tenemos una nueva herramienta: los objetos Task.
A continuación encontrarás algunos fragmentos de código útiles para crear tareas y organizar su ejecución. Dejo de lado el tratamiento de excepciones y el paso de parámetros para otro artículo.
- Para crear una tarea.
Imagínate que tienes un formulario, y que quieres ejecutar una tarea cuando se carga (por ejemplo, leer unos datos de la base de datos).
using System.Threading.Tasks;
....
private void Callejero_Load(object sender, EventArgs e)
{
Task t1 = new Task(
() =>
{
// Cargamos la lista de provincias en el control.
});
t1.Start();
}
Este método, define una tarea, solicita que se empiece a ejecutar, y sale sin esperar a que termine. El formulario seguirá respondiendo al usuario mientras ejecuta otras tareas en segundo plano.
Una cosa importante es que no puedes acceder a los controles del formulario desde un hilo distinto al que lo ha creado. Por ejemplo, la tarea no podrá cambiar el valor de una caja de texto del formulario directamente. Más adelante veremos un ejemplo de cómo hacerlo.
- Definir una tarea que se ejecute cuando otra termine.
Si tenemos una tarea T1 (como la anterior), y queremos definir una tarea T2 que se ejecute a continuación...
Task t2 = t1.ContinueWith(
ant =>
{
// Hacer más cosas
});
No es necesario llamar a Start() en una tarea de continuación (de hecho da un error). La tarea se arrancará automáticamente cuando T1 termine.
- Definir una tarea que se ejecute cuando varias tareas terminen.
Si tenemos dos tareas T1 y T2 que se van a ejecutar en paralelo, y queremos definir una tarea T3 que arranque cuando las otras dos terminen ...
Task t3 = Task.Factory.ContinueWhenAll(
new[] { t1, t2 },
tasks =>
{
// Hacemos más cosas
}
);
- Definir una tarea que se ejecute cuando otra termina, y actualice controles de nuestro formulario WPF.
Este es un caso muy típico. Imagínate que tienes un formulario que, cuando pulsas un botón, arranca una tarea T1. Cuando la tarea empieza, apagas un botón para que el usuario no le vuelva a dar. Cuando la tarea termina, quieres volver a habilitarlo. Nada más fácil.
Task t_final = t_1.ContinueWith(
ant =>
{
btn_procesar.IsEnabled = true;
}, TaskScheduler.FromCurrentSynchronizationContext());
- Definir una tarea que se ejecute cuando terminan otras, y actualice controles de nuestro formulario.
Task tarea_final = Task.Factory.ContinueWhenAll(
new[] { task_eventos, task_estados, task_info, task_parametros, task_control, task_canont },
tasks =>
{
// Accedemos a controles de nuestro formulario.
},
CancellationToken.None,
TaskContinuationOptions.None,
TaskScheduler.FromCurrentSynchronizationContext()
);
jueves, 21 de octubre de 2010
C# : Crear un fichero ZIP con múltiples ficheros.
¿Necesitas comprimir varios ficheros en una carpeta .ZIP para (por ejemplo) , enviarlos por correo?
En primer lugar, necesitas añadir vjslib.dll a las referencias de tu proyecto. Puedes hacerlo desde la solapa .NET del diálogo de referencias, o navegando a la carpeta ( C:\WINDOWS\Microsoft.NET\Framework\ o similar).
Actualización 15/11/12 : Si tienes problemas añadiendo la referencia, quizás necesites instalar el "Microsoft J# Redistributable Package" Puedes descargarlo de aquí
Una vez hayas añadido la referencia, podrás usar las clases de J# desde tu programa C#:
using java.util.zip;
using java.io;
Bien, pues suponiendo que tienes un array con los nombres de fichero a comprimir...
string[] ficheros_adjuntos = { "c:\\fich1.txt", "c:\\fich2.txt", "c:\\fich.txt" };
... y quieres crear una carpeta ZIP que los contenga ...
string nombre_fichero_salida = "c:\\fichero.zip";
El código sería similar a esto...
// Creamos un nuevo fichero zip
FileOutputStream streamSalida = new FileOutputStream( nombre_fichero_salida, false);
ZipOutputStream zipStream = new ZipOutputStream(streamSalida);
foreach (string fichero in ficheros_adjuntos)
{
sbyte[] contenido = new sbyte[1024];
int bytesLeidos = 0;
// Añadimos una entrada al fichero .zip Hay una entrada .zip por cada fichero que añadimos
ZipEntry ze = new ZipEntry(fichero.Replace ("c:\\" , ""));
zipStream.putNextEntry(ze);
// Volcamos el contenido del fichero de entrada al stream de compresión
FileInputStream fichero_entrada = new FileInputStream(fichero);
while ((bytesLeidos = fichero_entrada.read(contenido)) >= 0)
{
zipStream.write(contenido, 0 , bytesLeidos);
}
// Cerramos la entrada del fichero .zip y el fichero de entrada
zipStream.closeEntry();
fichero_entrada.close();
}
// Cerramos el stream y el fichero de salida
zipStream.close();
streamSalida.close();
Saludos.
En primer lugar, necesitas añadir vjslib.dll a las referencias de tu proyecto. Puedes hacerlo desde la solapa .NET del diálogo de referencias, o navegando a la carpeta ( C:\WINDOWS\Microsoft.NET\Framework\ o similar).
Actualización 15/11/12 : Si tienes problemas añadiendo la referencia, quizás necesites instalar el "Microsoft J# Redistributable Package" Puedes descargarlo de aquí
Una vez hayas añadido la referencia, podrás usar las clases de J# desde tu programa C#:
using java.util.zip;
using java.io;
Bien, pues suponiendo que tienes un array con los nombres de fichero a comprimir...
string[] ficheros_adjuntos = { "c:\\fich1.txt", "c:\\fich2.txt", "c:\\fich.txt" };
... y quieres crear una carpeta ZIP que los contenga ...
string nombre_fichero_salida = "c:\\fichero.zip";
El código sería similar a esto...
// Creamos un nuevo fichero zip
FileOutputStream streamSalida = new FileOutputStream( nombre_fichero_salida, false);
ZipOutputStream zipStream = new ZipOutputStream(streamSalida);
foreach (string fichero in ficheros_adjuntos)
{
sbyte[] contenido = new sbyte[1024];
int bytesLeidos = 0;
// Añadimos una entrada al fichero .zip Hay una entrada .zip por cada fichero que añadimos
ZipEntry ze = new ZipEntry(fichero.Replace ("c:\\" , ""));
zipStream.putNextEntry(ze);
// Volcamos el contenido del fichero de entrada al stream de compresión
FileInputStream fichero_entrada = new FileInputStream(fichero);
while ((bytesLeidos = fichero_entrada.read(contenido)) >= 0)
{
zipStream.write(contenido, 0 , bytesLeidos);
}
// Cerramos la entrada del fichero .zip y el fichero de entrada
zipStream.closeEntry();
fichero_entrada.close();
}
// Cerramos el stream y el fichero de salida
zipStream.close();
streamSalida.close();
Saludos.
viernes, 8 de octubre de 2010
Exportando e importando datos a Excel 2010 con C#
- Introducción.
A veces, la forma más elegante de presentar un listado a un usuario es generando una hoja de Excel con los datos. También puede ser útil leer datos de un libro de Excel, para procesarlos desde una aplicación C#.
Ambas tareas son una auténtica chorrada usando ADO: sólo hay que abrir el fichero de Excel como si fuera una base de datos cualquiera.
- Conexión
string plantilla = "TEMP\\prueba.xlsx";
string cadenaConexion = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="+plantilla+";Extended Properties=\"Excel 12.0 Xml;HDR=YES\"";
OleDbConnection con = new OleDbConnection(cadenaConexion);
con.Open();
El fichero "plantilla" puede o no existir. En este ejemplo vamos a crear uno nuevo.
Tienes más ejemplos de cadenas de conexión en http://www.connectionstrings.com/
- Definiendo una tabla.
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = con;
cmd.CommandText = @"create table [Hoja1] (F1 char(255), F2 char(255), F3 char(255))";
cmd.ExecuteNonQuery();
Esta orden creará un fichero llamado "prueba.xlsx" , y dentro una hoja llamada "Hoja1". En la primera fila de la hoja, aparecerán los nombres de campo F1, F2 y F3
- Insertando datos.
cmd.CommandText = @"insert into [Hoja1$] (F1, F2, F3) values (1, 2, 3)";
cmd.ExecuteNonQuery();
Los datos se insertarán en la primera fila libre tras la cabecera.
- Actualizando datos.
Como ya te habrás imaginado, actualizar datos es tan sencillo como ...
cmd.CommandText = @"update [Hoja1$] set F2 = '4' where F1 = '1'";
cmd.ExecuteNonQuery();
- Leyendo datos.
cmd.CommandText = "select * from [Hoja1$] order by F1";
OleDbDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
// hacemos cosas con los datos
}
dr.Close();
- Para terminar.
Cerramos la conexión...
con.Close();
Si estás exportando datos, probablemente querrás abrir el fichero de Excel para que el usuario no tenga que buscarlo y abrirlo él.
System.Diagnostics.Process p = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo(plantilla);
info.UseShellExecute = true;
p.StartInfo = info;
while(!p.Start());
Espero que te sea útil :)
A veces, la forma más elegante de presentar un listado a un usuario es generando una hoja de Excel con los datos. También puede ser útil leer datos de un libro de Excel, para procesarlos desde una aplicación C#.
Ambas tareas son una auténtica chorrada usando ADO: sólo hay que abrir el fichero de Excel como si fuera una base de datos cualquiera.
- Conexión
string plantilla = "TEMP\\prueba.xlsx";
string cadenaConexion = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source="+plantilla+";Extended Properties=\"Excel 12.0 Xml;HDR=YES\"";
OleDbConnection con = new OleDbConnection(cadenaConexion);
con.Open();
El fichero "plantilla" puede o no existir. En este ejemplo vamos a crear uno nuevo.
Tienes más ejemplos de cadenas de conexión en http://www.connectionstrings.com/
- Definiendo una tabla.
OleDbCommand cmd = new OleDbCommand();
cmd.Connection = con;
cmd.CommandText = @"create table [Hoja1] (F1 char(255), F2 char(255), F3 char(255))";
cmd.ExecuteNonQuery();
Esta orden creará un fichero llamado "prueba.xlsx" , y dentro una hoja llamada "Hoja1". En la primera fila de la hoja, aparecerán los nombres de campo F1, F2 y F3
- Insertando datos.
cmd.CommandText = @"insert into [Hoja1$] (F1, F2, F3) values (1, 2, 3)";
cmd.ExecuteNonQuery();
Los datos se insertarán en la primera fila libre tras la cabecera.
- Actualizando datos.
Como ya te habrás imaginado, actualizar datos es tan sencillo como ...
cmd.CommandText = @"update [Hoja1$] set F2 = '4' where F1 = '1'";
cmd.ExecuteNonQuery();
- Leyendo datos.
cmd.CommandText = "select * from [Hoja1$] order by F1";
OleDbDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
// hacemos cosas con los datos
}
dr.Close();
- Para terminar.
Cerramos la conexión...
con.Close();
Si estás exportando datos, probablemente querrás abrir el fichero de Excel para que el usuario no tenga que buscarlo y abrirlo él.
System.Diagnostics.Process p = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo info = new System.Diagnostics.ProcessStartInfo(plantilla);
info.UseShellExecute = true;
p.StartInfo = info;
while(!p.Start());
Espero que te sea útil :)
Suscribirse a:
Entradas (Atom)
