elhacker.net cabecera Bienvenido(a), Visitante. Por favor Ingresar o Registrarse
¿Perdiste tu email de activación?.


 


Tema destacado: Únete al Grupo Steam elhacker.NET


+  Foro de elhacker.net
|-+  Programación
| |-+  Programación General
| | |-+  .NET (C#, VB.NET, ASP) (Moderador: kub0x)
| | | |-+  Cerrar aplicación mientras ser reproduce un bucle Do/Loop
0 Usuarios y 1 Visitante están viendo este tema.
Páginas: [1] Ir Abajo Respuesta Imprimir
Autor Tema: Cerrar aplicación mientras ser reproduce un bucle Do/Loop  (Leído 2,131 veces)
Lekim

Desconectado Desconectado

Mensajes: 268



Ver Perfil
Cerrar aplicación mientras ser reproduce un bucle Do/Loop
« en: 19 Octubre 2015, 01:13 »

Hola

Hola me gustaría saber como salir de la aplicación cuando todavía no se a salido de DO/LOOP

Mi método clásico siempre ha sido poner END en el evento Unload en VB y también en Dispose en Net. No se si habrá otra manera también sencilla.

Por ejemplo he creado un Bucle Do/Loop en el que creo un reloj en el cual si han pasado 10 segundos se sale de del bucle. La razón es porque quiero que el bucle dure un mínimo de 10 segundos a espera que se cumpla una condición y si pasados los 10 segundos no se cumple sale del bucle.

Aquí va el supercódigo de ejemplo :P
Código
  1. Option Strict On
  2. Option Explicit On
  3. Public Class Form1
  4.  
  5.    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  6.        Dim SecA As TimeSpan, SecB As TimeSpan
  7.        SecA = TimeSpan.FromTicks(Date.Now.Ticks)
  8.        Do
  9.            SecB = TimeSpan.FromTicks(Date.Now.Ticks).Subtract(SecA)
  10.            Me.Text = CStr(SecB.Seconds)
  11.            If CInt(SecB.Seconds) = 10 Then Exit Do
  12.            My.Application.DoEvents()
  13.        Loop 'While (podría poner condición y si se cumple sale antes de los 10 segundos)
  14.    End Sub
  15.  
  16.    Private Sub Form1_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
  17.        End
  18.    End Sub
  19. End Class

El problema está en que si quito
 
Código
  1.    Private Sub Form1_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
  2.        End
  3.    End Sub
  4.  

No se puede cerrar la apliación hasta que no pasen los 10 segundos


« Última modificación: 19 Octubre 2015, 01:18 por Lekim » En línea

El Benjo


Desconectado Desconectado

Mensajes: 390



Ver Perfil WWW
Re: Cerrar aplicación mientras ser reproduce un bucle Do/Loop
« Respuesta #1 en: 19 Octubre 2015, 06:41 »

Lo puedes hacer de varias maneras, la más sencilla es mediante una variable que le diga al loop si la aplicación se ha cerrado, cambiando el estado de esta variable cuando se esté cerrando el form:

Código
  1. Public Class Form1
  2.  
  3. Dim AplicacionCerrada As Boolean = False
  4.  
  5. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
  6.        Dim SecA As TimeSpan, SecB As TimeSpan
  7. SecA = TimeSpan.FromTicks(Date.Now.Ticks)
  8. Do
  9. SecB = TimeSpan.FromTicks(Date.Now.Ticks).Subtract(SecA)
  10. Me.Text = CStr(SecB.Seconds)
  11. If CInt(SecB.Seconds) = 10 Then Exit Do
  12. My.Application.DoEvents()
  13. If AplicacionCerrada = True Then End
  14. Loop 'While (podría poner condición y si se cumple sale antes de los 10 segundos)
  15. End Sub
  16.  
  17. Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
  18. AplicacionCerrada = True
  19. End Sub
  20.  
  21. End Class

También puedes hacerlo usando un hilo independiente, pero necesitarías utilizar delegados y usar la propiedad InvokeRequired y la función Invoke() del formulario. Espero que el primer método te sirva.


En línea

www.es.neftis-ai.com

Sí hay un mejor lenguaje de programación y es ese con el que puedes desarrollar tus objetivos.
Eleкtro
Ex-Staff
*
Desconectado Desconectado

Mensajes: 9.709



Ver Perfil
Re: Cerrar aplicación mientras ser reproduce un bucle Do/Loop
« Respuesta #2 en: 19 Octubre 2015, 13:33 »

Terminar la ejecución de la aplicación de forma anómala usando el keyword End es algo que se debe evitar a toda costa, de todas formas en el handler donde indicas esa orden es normal que no te funcione como esperas.

Lo que deberías hacer es lo que ha comentado @El_Benjo al final de su comentario. Puedes utilizar un BackgroundWorker o mejor una Task con un token de cancelación en el cual realizarías una petición de cancelación al cerrar el form.

Aparte de eso, deberías reemplazar el uso de TimeSpan por un StopWatch, ya que la medida es más precisa y su utilización más simple.

Saludos
« Última modificación: 19 Octubre 2015, 13:39 por Eleкtro » En línea


Lekim

Desconectado Desconectado

Mensajes: 268



Ver Perfil
Re: Cerrar aplicación mientras ser reproduce un bucle Do/Loop
« Respuesta #3 en: 19 Octubre 2015, 23:41 »

Gracias  los dos ;-)


No estoy seguro que opción es mejor pero creo que por sencillez me decanto por usar la variable boleana.

He aprovechado para realizar un experimento de velocidad de los procesos dentro del bucle, para este ejemplo, que imagino que según el ordenador los resultados será  distinto.

Código
  1. Option Explicit On
  2. Option Strict On
  3. Imports System.Text
  4. Public Class Form1
  5.    Dim AplicacionCerrada As Boolean = False
  6.    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  7.        Dim stopWatch As New Stopwatch() : Dim ts As TimeSpan : Dim elapsedTime As String = Nothing
  8.        Dim Cont As Integer = 0
  9.  
  10.        stopWatch.Start()
  11.        Do
  12.            Cont += 1
  13.            ts = stopWatch.Elapsed
  14.            String.Format("{00}", ts.Seconds)
  15.  
  16.            '///Experimeto que mide el número de procesos por segundo
  17.            Dim Datos As New StringBuilder
  18.            With Datos
  19.                .AppendFormat("Procesos: {0}", CInt(Cont))
  20.                .AppendLine()
  21.                .AppendFormat("Segundos: {0}", ts.Seconds)
  22.                .AppendLine()
  23.                .AppendFormat("Velocidad: {0}", (CInt(Cont) / (CInt(ts.Seconds))).ToString("0.000") & " Proc/s")
  24.            End With
  25.            Label1.Text = Datos.ToString
  26.            '/////////////////////////////////////////////////////////////////////////
  27.  
  28.            If AplicacionCerrada = True Then End
  29.            If ts.Seconds = 10 Then stopWatch.Stop() : Exit Do
  30.            My.Application.DoEvents()
  31.        Loop While Cont < 14000
  32.    End Sub
  33.    Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs) Handles MyBase.FormClosing
  34.        AplicacionCerrada = True
  35.    End Sub
  36. End Class
  37.  




Esta sería la otra forma, aunque más compleja y que me ha costado encontrar.

Código
  1. Option Explicit On
  2. Option Strict On
  3. Imports System.Threading.Tasks
  4. Imports System.Text
  5.  
  6. Public Class Form1
  7.  
  8.    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
  9.        Dim stopWatch As New Stopwatch() : Dim ts As TimeSpan : Dim elapsedTime As String = Nothing
  10.        Dim Cont As Integer = 0
  11.  
  12.        Task.Factory.StartNew(Sub()
  13.  
  14.                                  stopWatch.Start()
  15.                                  'Desactivar el chequeo sobre acceso de varios subprocesos
  16.                                  ' CheckForIllegalCrossThreadCalls = False
  17.  
  18.                                  Do
  19.                                      Cont += 1
  20.                                      ts = stopWatch.Elapsed
  21.                                      String.Format("{00}", ts.Seconds)
  22.                                      '///Experimeto que mide el número de procesos por segundo
  23.                                      Dim Datos As New StringBuilder
  24.                                      With Datos
  25.                                          .AppendFormat("Procesos: {0}", CInt(Cont))
  26.                                          .AppendLine()
  27.                                          .AppendFormat("Segundos: {0}", ts.Seconds)
  28.                                          .AppendLine()
  29.                                          .AppendFormat("Velocidad: {0}", (CInt(Cont) / (CInt(ts.Seconds))).ToString("0.000") & " Proc/s")
  30.                                      End With
  31.                                      Label1.Invoke(CType(Sub() Label1.Text = Datos.ToString, MethodInvoker))
  32.                                      '/////////////////////////////////////////////////////////////////////////
  33.                                      If ts.Seconds = 10 Then stopWatch.Stop() : Exit Do
  34.                                      '  My.Application.DoEvents()
  35.                                  Loop While Cont < 14000
  36.  
  37.                              End Sub).ContinueWith(Sub()
  38.                                                        Me.Invoke(Sub()
  39.                                                                      Me.Text = "Proceso terminado"
  40.                                                                  End Sub)
  41.                                                    End Sub)
  42.    End Sub
  43. End Class
  44.  


De esta última forma usando Task e Invoke como habéis dicho el programa se cierra sin problemas.

Me ha costado averiguar también como llamar a un control externo dentro de un subproceso, ya que si llamaba diréctamente obtenía error. La forma era la siguiente:

Código
  1. Label1.Invoke(DirectCast(Sub() Label1.Text = Datos, MethodInvoker))

También:
Código
  1. Me.Invoke(Sub()
  2.        Me.Text = "Proceso terminado"
  3.        End Sub)


En cuanto a la eficiencia creo que es lo mismo porque me dan resultados idénticos, me refiero al experimento.

Si el ordenador es al menos normalito, debería salir del bucle antes de los 10 segundos.

Saludos
« Última modificación: 20 Octubre 2015, 14:22 por Lekim » En línea

Eleкtro
Ex-Staff
*
Desconectado Desconectado

Mensajes: 9.709



Ver Perfil
Re: Cerrar aplicación mientras ser reproduce un bucle Do/Loop
« Respuesta #4 en: 21 Octubre 2015, 07:42 »

En caso de que hayas optado por utilizar la alternativa de la Task, ten en cuenta como dije que la forma en la que lo debes hacer es asignándole un token de cancelación, cuyo nombre sirve para cancelar la tarea evidentemente, entonces lo usas y seguidamente utilizas el método Task.Wait para esperar a que la tarea finalice su cancelación antes de cerrar/liberar el form, de lo contrario se lanzará una excepción de tipo ObjectDisposedException al intentar invokar el control cuando ya ha sido liberado.

No es que sea muy importante ya que la excepción ocurrirá en el thread secundario, es decir, no saltará un mensaje de error ni nada en el thread de la UI, la excepción la podrás ver al depurar la app pero el form se cerrará como estaba previsto sin mostrar nada, de todas formas lo comento por que siempre es buena costumbre intentar evitar o controlar cualquier excepción que podamos preveer con antelación, en la medida de lo posible.

Saludos!
« Última modificación: 21 Octubre 2015, 08:08 por Eleкtro » En línea


Lekim

Desconectado Desconectado

Mensajes: 268



Ver Perfil
Re: Cerrar aplicación mientras ser reproduce un bucle Do/Loop
« Respuesta #5 en: 21 Octubre 2015, 09:54 »

Ok Elektro  :)

Encontré lo que comentas aquí. Lo probaré cuando pueda.

 CANCELACIÓN DE SUBPROCESOS ADMINISTRADOS

Saludos
En línea

Páginas: [1] Ir Arriba Respuesta Imprimir 

Ir a:  

Aviso Legal - Powered by SMF 1.1.21 | SMF © 2006-2008, Simple Machines