Colabora
 

Precarga con animación para aplicaciones WindowsForm con BackgroundWorker

[Precarga con efecto opacidad sobre tu aplicación WindowsForm lanzando procesos en background con BackgroundWorker]

 

Fecha: 12/Sep/2009 (06-09-09)
Autor: Daniel J Rodriguez Perez [danicuco]- [email protected]

www.danicuco.com & www.danicuco.es

 


Introducción

Muchas veces nos vemos en la obligación de lanzar algún que otro tipo de ejecución en segundo plano por motivos varios y con la ayuda del objeto BackGroundWorker, una barrita de progreso y deshabilitando los controles para impedir la invocación de otros eventos se realiza una solución óptima.

Pero en una ocasión mi compañero me comentaba que necesitaba algo especial y que fuese original (o por lo menos que lo intentara).

Entonces recordé un proyecto web en el que trabajé (que si no recuerdo mal fue mi primer trabajo) y donde usaban las archiconocidas capas con trasparencia y los "cargando... , espere por favor", hoy en día muy usados en casi todas las web, y se me ocurrió la idea de aplicarlo en una aplicación WindowsForm surgiendo entonces la clase frmPreload.vb que no es más que una simple clase que lanza una animación visual sobre cualquier formulario que la invoque y donde se juega con la propiedad opacity de los controles form e impidiendo la ejecución de otros eventos hasta que no finalice el subproceso... espero que os surjan muchas ideas a partir de esta colaboración

(Un enorme saludo al equipo de desarrollo .NET de CORPME).

 

¿Como queda visualmente nuestro frmPreload.vb?

Nuestro primer paso... Entender lo que realmente está sucediendo

En el ejemplo que he utilizado he creado un formulario MDI que será el encargado de lanzar el proceso en background  y de visualizar el formulario preload (de aquí en adelante frmPreload). Lo que realmente sucede es que cuando usuario invoque el evento que lanza el subproceso en background, frmpreload se superpone al formulario que le invoca quedando frmPreload ejecutándose en el hilo principal y el subproceso "costoso" en segundo plano. Con esto conseguimos que el usuario no pueda ejecutar ningún tipo de acción sobre FormMDI hasta que el subproceso haya finalizado o haya completado su ejecución.
En la siguiente imagen muestro gráficamente lo que ocurre. Un formulario con opacidad, gif animado y una label descriptiva  se superpone a otro formulario.

Efecto Preload

Nota:
Como es lógico el frmPreload es una clase que hereda de window.form y en su constructor se encarga de localizar y “sizearse” según el tamaño del invocador, a su vez frmPreload controla si el usuario maximiza o minimiza el formulario formMDI desde la barra de tareas y deshabilita ctrl+f4. Es evidente que tan solo es algo básico y muy mejorable. Pero eso ya lo dejo en el duende de cada uno.

Dejo como ejemplo de funcionamiento de la clase frmPreload el método que se encarga de localizar al invocador y su vez centrar tanto el label como el gif de animación del frmPreload según los valores del size y del location.

    Private Sub inicializarPreload(ByVal _form As System.Windows.Forms.Form)
        'Supendemos el diseño
        Me.SuspendLayout()
        Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
        Me.ShowInTaskbar = False

        '' Localizacion Inicial de los objetos
        mLocationInicialPic = Me.picAjax.Location
        mLocationInicialLab = Me.lbTextoPreload.Location
        '' Size inicial del formpreload
        mSizeInicialPreload = Me.Size
        '' Aplicamos el size y location del formulario ....
        Me.Size = _form.Size
        Me.Location = _form.Location
        '' Obtenemos el factor Localizacion con este algoritmo
        factorEscalaX = (_form.Size.Width - mSizeInicialPreload.Width) / 2
        factorEscalaY = (_form.Size.Height - mSizeInicialPreload.Height) / 2

        '' A la localizacion inicial del picture sumamos eel nuevo valor obtenido
        mLocationInicialPic.X += factorEscalaX
        mLocationInicialPic.Y += factorEscalaY
        '' Idem a label
        mLocationInicialLab.X += factorEscalaX
        mLocationInicialLab.Y += factorEscalaY

        '' Aplicamos nuevas localizaciones 
        Me.picAjax.Location = New System.Drawing.Point(mLocationInicialPic.X, mLocationInicialPic.Y)
        Me.lbTextoPreload.Location = _
		 New System.Drawing.Point(mLocationInicialLab.X, mLocationInicialLab.Y)

        'Reiniciamos el diseño
        Me.ResumeLayout()
    End Sub

Una vez cogida la sartén por el mango a cocinar se dijo:

Como ya hemos comprendido lo que realmente queremos simular, en nuestro ejemplo será el clic del botón nuevo fichero del formMDI el que lance nuestro proceso "costoso" y a su vez quien instancie y visualice nuestro preload

A continuación detallo alguno de los métodos y eventos encargados de instanciar y visualizar la clase frmPreload y que habría que implementar en nuestro FormMDI.

  
     ''' Como instanciar la clase frmPreload desde el evento clik de un boton y seguidamente
     ''' lanzar un proceso en segundo plano con el componente BackGroundWorker

    Private Sub ClickBoton(ByVal sender As Object, ByVal e As EventArgs) 
Handles NewToolStripMenuItem.Click, NewToolStripButton.Click ' Supendemos la logica de diseño Me.SuspendLayout() ' Instanciamos el obj frmPreload para este invocador wfPrecarga = New frmPreload(Me) ' Mostramos wfPrecarga.Show() ' Forzamos la logica de diseño Me.ResumeLayout(True) ' Obligamos a refrescar el area de diseño inmediatamente wfPrecarga.Refresh() ' Finalmente lanzamos el subhilo de ejecucion bwPrecarga.RunWorkerAsync() End Sub ***********************EVENTOS BACKGROUND WORKER ************************** Evento DoWork del componente BackGroundWorker Private Sub bwPrecarga_DoWork(ByVal sender As Object, ByVal e As _ System.ComponentModel.DoWorkEventArgs)Handles bwPrecarga.DoWork ' Nota: Como yo no tengo proceso "costoso" lanzo una "iteracion dormida" cada medio segundo. For index As Integer = 1 To 10 Threading.Thread.Sleep(500) Next * AQUI TU CODIGO * End Sub ''' Evento RunWorkerCompleted Private Sub bwPrecarga_RunWorkerCompleted(ByVal sender As Object, ByVal e As _ System.ComponentModel.RunWorkerCompletedEventArgs) Handles bwPrecarga.RunWorkerCompleted wfPrecarga.Dispose() End Sub **********************************************************************************************

Nota:
Recordar que tenemos que añadir un objeto a nuestro FormMDI del tipo BackgroundWorker desde la barra de herramientas, yo en mi caso lo he llamado "bwPrecarga"

Espero haberme explicado con claridad y no haber dejado ningún tipo de duda a la hora de implementar la clase frmPreload.vb, aun así he decidido acompañarlo de un Zip con un ejemplo en funcionamiento y donde se puede ver el código completo.

Danicuco 2009.

 


Espacios de nombres usados en el código de este artículo:

System.Windows.Forms

 



Compromiso del autor del artículo con el sitio del Guille:

Lo comentado en este artículo está probado (y funciona) con la siguiente configuración:

El autor se compromete personalmente de que lo expuesto en este artículo es cierto y lo ha comprobado usando la configuración indicada anteriormente.

En cualquier caso, el Guille no se responsabiliza del contenido de este artículo.

Si encuentras alguna errata o fallo en algún link (enlace), por favor comunícalo usando este link:

Gracias.


Código de ejemplo (comprimido):

 

Fichero con el código de ejemplo: danicuco_Precarga_WindowsForm_BackGorundWorker_Codigo.zip - 31.00 KB

(MD5 checksum: CC31C14CF4386911D80F44688C8E8B0C)

 


Ir al índice principal de el Guille