Estoy tratando de agregarle un contador a una copia, pero no e logrado de que este se me actualice sin la necesidad de actualizar el form. Esto es lo que tengo.
for
File.Copy(RutaOrigen, RutaGF, True)
FCopy.Text = "1" + Val(FCopy.Text)
Me.Text = ListBox1.Items.Count.ToString() & ".Archivos"
Me.Refresh()
next
Al refrescar me parpadea el form.
La idea es que este me enumere la cantidad de ficheros copiados.
Saludos y gracias.
Cita de: Tomas1982 en 26 Enero 2017, 16:00 PMEstoy tratando de agregarle un contador a una copia
Hola. El problema que has planteado carece de la información necesaria, para empezar la sentencia del For está incompleta / no es compilable. Intenta ser más específico la próxima vez y al menos aportar un código/ejemplo funcional... no nos hagas asumir las cosas, esto es programación y requiere todos los detalles posibles por tu parte para evitar asunciones y preguntas recurrentes.
Cita de: Tomas1982 en 26 Enero 2017, 16:00 PMse me actualice sin la necesidad de actualizar el form.
Lo que ocurre es que estás realizando una operación "bloqueante" en el thread de la UI, es decir, estás ejecutando un búcle en el thread de la UI y hasta que el bloque del For no termine su ejecuión no podrás hacer nada más. Aparte de eso, refrescar el Form por completo es una operación expensiva y no hay necesidad de ello, en todo caso deberías refescar el Label/Control en el que necesites actualizar "X" información llamando al método
Control.Update().
Con respecto al problema del bloqueo de la UI, la solución apropiada para llevar a cabo esto no es "hacer click y listo", se necesita un previo entendimiento y práctica por tu parte sobre la programación asincrónica en general. De todas formas te mostraré un ejemplo que puedes adaptar donde además te muestro el uso del paralelismo para acelerar la operación de copiado de archivos (o no. Depende, mientras no sean archivos de gran tamaño ok)...
En fin, lo que hace el siguiente código, aparte de evitar el bloqueo de la UI claro está, es realizar una copia NO-recursiva de los archivos del directorio "A" al directorio "B", y mostrar el progreso de archivos copiados en el control que le pasemos a la función, en este caso un label.
Imports System.IO
Imports System.Threading
Public NotInheritable Class Form1 : Inherits Form
Private Async Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
Dim copyTask As Task(Of Integer) = Me.CopyFiles("C:\Source\", "C:\Destination\", Me.Label1)
Await Task.WhenAll(copyTask)
MessageBox.Show(String.Format("Files copied: {0}", copyTask.Result))
End Sub
Public Async Function CopyFiles(ByVal srcDirPath As String, ByVal dstDirPath As String, ByVal progressCtrl As Control) As Task(Of Integer)
Dim files As IEnumerable(Of FileInfo) = New DirectoryInfo(srcDirPath).EnumerateFiles("*", SearchOption.TopDirectoryOnly)
Dim maxFileCount As Integer = files.Count()
Dim curFileCount As Integer
Dim updateLabelCallback As New SendOrPostCallback(
Sub(ByVal state As Object)
progressCtrl.Text = String.Format("{0} of {1} files copied...", CInt(state), maxFileCount)
End Sub)
Dim copySingleFileAction As New Action(Of FileInfo)(
Sub(ByVal file As FileInfo)
Try
file.CopyTo(Path.Combine(dstDirPath, file.Name), overwrite:=True)
SynchronizationContext.Current.Post(updateLabelCallback, Interlocked.Increment(curFileCount))
Catch ex As Exception
End Try
End Sub)
Dim copyAllFilesFunc As Func(Of Integer) =
Function() As Integer
Parallel.ForEach(Of FileInfo)(files, copySingleFileAction)
Return curFileCount ' Return the amount of files copied.
End Function
If Not New DirectoryInfo(dstDirPath).Exists Then
Directory.CreateDirectory(dstDirPath, Nothing)
End If
Dim t As New Task(Of Integer)(copyAllFilesFunc, TaskCreationOptions.LongRunning)
t.Start()
Await t
Return t.Result
End Function
End Class
Si por el momento este tipo de solución asincrónica te resultase incomprensible, entonces siempre puedes recurrir a llamar al método
Application.DoEvents() en el For que has compartido al principio, y listo, pero te advierto que hacer eso es programación irresponsable y deberías evitarlo a toda costa por varios motivos que no viene al caso explicar ahora (a menos que tengas esa duda).
Ejemplo:
Dim counter As Integer
for ...
File.Copy(RutaOrigen, RutaGF, overwrite:=True)
FCopy.Text = CStr(Threading.Thread.Interlocked.Increment(counter))
' Descomentar en caso de que el valor no se actualice correctamente:
' FCopy.Update()
Application.DoEvents()
next
Saludos!
Eleкtro: Evidentemente ese no es el código, simplemente quise poner una idea de lo que quería, como lo explique. El código completo donde realizo la copia es este.
Private Sub Organizar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Organizar.Click
If TextBox1.Text = "" Then
MessageBox.Show("Seleccionar ruta origen", "Ruta...")
ElseIf TextBoxDestino.Text = "" Then
MessageBox.Show("Seleccione ruta Destino", "Ruta...")
End If
'Recorre el Listbox item por item
Try
For i As Integer = 0 To Me.ListBox1.Items.Count - 1
RutaOrigen = ListBox1.Items(i)
'Obtener el nombre del fichero
NDFichero = Path.GetFileName(RutaOrigen)
'Obtener la extensión del fichero
ExtFichero = Path.GetExtension(RutaOrigen)
'Le quito el punto para usarlo en el nombre de la carpeta
Dim MyChar() As Char = {"."}
NCConExt = ExtFichero.TrimStart(MyChar)
Console.WriteLine(NCConExt)
'Crea el directorio si no existe
If Not Directory.Exists(RutaDestino & "\" & NCConExt & "\") Then
Directory.CreateDirectory(RutaDestino & "\" & NCConExt & "\")
End If
'Prepara la ruta mas el fichero a copiar
RDestino = RutaDestino & "\" & NCConExt & "\" & ExtFichero
'Try
If System.IO.File.Exists(RDestino) Then
'<<El archivo a copiar ya existe en destino>>
'Obtiene nombre del archivo sin extensión
Dim sFileName As String = ExtFichero.Substring(0, ExtFichero.Length - ExtFichero.ToString.Length)
Dim num As Integer = Nothing
While System.IO.File.Exists(RDestino) 'Cambia el
num += 1
'Renombra archivo en destino. Ej: C:\Organizado\ext\file(1).ext
RDestino = String.Format("{0}{1}({2}){3}", RutaDestino & "\" & NCConExt & "\", sFileName, num, ExtFichero)
End While
End If
Try
If RadioButton1.Checked = True Then
File.Copy(CStr(RutaOrigen), RDestino, False)
Else
File.Move(CStr(RutaOrigen), RDestino)
End If
'Muestra el fichero que se esta copiando
RutDFichero.Text = RutaOrigen
RutDFichero.Update()
Catch ex As Exception
MsgBox("Error: " & ex.Message)
End Try
FCopy.Text = "1" + Val(FCopy.Text)
FCopy.Update()
Next
Catch ex As Exception
MsgBox("No se realizó la operación por: " & ex.Message)
End Try
Dim result As Integer = MessageBox.Show("Operación terminada> Deseas limpiar los datos", "caption", MessageBoxButtons.YesNo)
If result = DialogResult.No Then
Exit Sub
ElseIf result = DialogResult.Yes Then
Limpiardatos()
End If
End Sub
Darle una revisada para ver que me va mal y corregirlo. Saludossss
Cita de: Tomas1982 en 31 Enero 2017, 20:06 PMDarle una revisada para ver que me va mal y corregirlo.
Hola.
Aquí no se aceptan órdenes, ni tampoco le hacemos el trabajo a nadie.
Debo comentar algo, y es que ha habido una pequeña confusión. La primera vez que leí tu post donde explicaste el problema, por algún motivo me rallé (lo lei deprisa o algo, no se) y pensé que te referias a un problema de bloqueo de la UI, no a un problema de flickering, y te mostré dos soluciones diferentes enfocadas a evitar el bloqueo de la UI (que no el flickering), lo siento por eso. Lo bueno de esto es que de todas formas puedes aprovechar el primer ejemplo (el asincrónico) para adaptarlo y evitar llamar a "Me.Refresh()" ya que refrescar el Form/Todos los controles es el causante de lo que te ocurre. Empieza por leer a fondo la respuesta que te di donde digo que debes hacer en lugar de llamar a "Me.Refresh", y adaptar a tus necesidades aquél que mostré código. Ah, y para reducir (o en el mejor de los casos evitar) el flickering en WindowsForms siempre es bueno que actives la propiedad
DoubleBuffered de tu Form.
Saludos.