Informar el progreso a los controles de la forma principal desde una tarea pesada roscada -- # campo con winforms campo con async-await camp codereview Relacionados El problema

Reporting progress to main form's controls from within a threaded heavy task


3
vote

problema

Español

Estoy tratando de descubrir cómo escribir bien una aplicación WinForms que informa el progreso de completar una tarea larga en los controles de la forma principal sin causar excepciones de OP de hilo cruzado y demás. Hasta ahora, he llegado con este esquema que al menos funciona, pero no se ve muy bien:

  Progress<MyProgress> progress = new Progress<MyProgress>(); private void Form1_Load(object sender, EventArgs e)  {     progress.ProgressChanged += (x, y) =>         Invoke(new Action(() => { toolStripStatusLabel1.Text = y.text;                                   toolStripProgressBar1.Value = y.percentage; })); }  bool DoVeryHeavyStuff(IProgress<MyProgress> progress) {     progress.Report(new MyProgress() { percentage = 0, text = "Doing heavy stuff…" }); }  async void button_doHeavyStuff_Click(object sender, EventArgs e) {     bool success = await Task.Run(() => DoVeryHeavyStuff(progress)); }   

Como puede ver, la parte derecha del progress.ProgressChanged += se ve demasiado complejo. ¿No hay una forma en que se puede escribir más simplemente?

Una cosa que podía pensar es crear un método separado, pero eso no ayudaría mucho, ya que todavía tendría que ser referido en esa línea.

  progress.ProgressChanged += (x, y) =>     Invoke(new Action(() => progress_ProgressChanged(x, y)));  void progress_ProgressChanged(object sender, MyProgress e)     {         toolStripStatusLabel1.Text = e.text;         toolStripProgressBar1.Value = e.percentage;     }   

Me las arreglé para separarlo así, pero parece peor aún:

  from collections import defaultdict class Graph:     def __init__(self):         self.connections = defaultdict(list)         self.visited = set()         self.shortest_path = defaultdict(list)         self.shortest_path_distance = defaultdict(lambda : float('inf'))     def add_edge(self, edge):         self.connections[edge[0]].append((edge[1], edge[2]))         self.connections[edge[1]].append((edge[0], edge[2]))     def calculate_shortest_path(self, cur, max_path_stop):         self.visited.add(cur)         self.shortest_path[cur] = [cur]         self.shortest_path_distance[cur] = 0         for n,d in self.connections[cur]:             self.shortest_path_distance[n] = d             self.shortest_path[n].append(cur)             self.shortest_path[n].append(n)         while (len(self.visited) < len(self.connections.keys())):             shortest_so_far = float('inf')             shortest_node_so_far = None             for n,d in self.shortest_path_distance.items():                 if n in self.visited:                     continue                 if d <= shortest_so_far:                     shortest_node_so_far = n                     shortest_so_far = d             self.visited.add(shortest_node_so_far)             for n in self.connections[shortest_node_so_far]:                 if self.shortest_path_distance[shortest_node_so_far] + n[1] < self.shortest_path_distance[n[0]]                          and len(self.shortest_path[shortest_node_so_far]+[n[0]])-1 <= max_path_stop:                     self.shortest_path_distance[n[0]]=self.shortest_path_distance[shortest_node_so_far] + n[1]                     self.shortest_path[n[0]]=self.shortest_path[shortest_node_so_far]+[n[0]] if __name__ == "__main__":     g = Graph()     edges = [(1,2,7),(1,3,9),(1,6,14),(2,3,10),(3,6,2),(5,6,9),(5,4,6),(3,4,11),(2,4,15)]     for e in edges:         g.add_edge(e)     g.calculate_shortest_path(1,2)     print g.shortest_path     print g.shortest_path_distance 0  

from collections import defaultdict class Graph: def __init__(self): self.connections = defaultdict(list) self.visited = set() self.shortest_path = defaultdict(list) self.shortest_path_distance = defaultdict(lambda : float('inf')) def add_edge(self, edge): self.connections[edge[0]].append((edge[1], edge[2])) self.connections[edge[1]].append((edge[0], edge[2])) def calculate_shortest_path(self, cur, max_path_stop): self.visited.add(cur) self.shortest_path[cur] = [cur] self.shortest_path_distance[cur] = 0 for n,d in self.connections[cur]: self.shortest_path_distance[n] = d self.shortest_path[n].append(cur) self.shortest_path[n].append(n) while (len(self.visited) < len(self.connections.keys())): shortest_so_far = float('inf') shortest_node_so_far = None for n,d in self.shortest_path_distance.items(): if n in self.visited: continue if d <= shortest_so_far: shortest_node_so_far = n shortest_so_far = d self.visited.add(shortest_node_so_far) for n in self.connections[shortest_node_so_far]: if self.shortest_path_distance[shortest_node_so_far] + n[1] < self.shortest_path_distance[n[0]] and len(self.shortest_path[shortest_node_so_far]+[n[0]])-1 <= max_path_stop: self.shortest_path_distance[n[0]]=self.shortest_path_distance[shortest_node_so_far] + n[1] self.shortest_path[n[0]]=self.shortest_path[shortest_node_so_far]+[n[0]] if __name__ == "__main__": g = Graph() edges = [(1,2,7),(1,3,9),(1,6,14),(2,3,10),(3,6,2),(5,6,9),(5,4,6),(3,4,11),(2,4,15)] for e in edges: g.add_edge(e) g.calculate_shortest_path(1,2) print g.shortest_path print g.shortest_path_distance 1 parece ser esencial para evitar excepciones de hilo cruzado, pero requiere un delegado como un parámetro. No tengo mucha experiencia con los delegados, por lo que no sé cómo simplificar el código de inicialización de la acción.

Parece que no puedo dejar simplemente dejar el reparto explícito a from collections import defaultdict class Graph: def __init__(self): self.connections = defaultdict(list) self.visited = set() self.shortest_path = defaultdict(list) self.shortest_path_distance = defaultdict(lambda : float('inf')) def add_edge(self, edge): self.connections[edge[0]].append((edge[1], edge[2])) self.connections[edge[1]].append((edge[0], edge[2])) def calculate_shortest_path(self, cur, max_path_stop): self.visited.add(cur) self.shortest_path[cur] = [cur] self.shortest_path_distance[cur] = 0 for n,d in self.connections[cur]: self.shortest_path_distance[n] = d self.shortest_path[n].append(cur) self.shortest_path[n].append(n) while (len(self.visited) < len(self.connections.keys())): shortest_so_far = float('inf') shortest_node_so_far = None for n,d in self.shortest_path_distance.items(): if n in self.visited: continue if d <= shortest_so_far: shortest_node_so_far = n shortest_so_far = d self.visited.add(shortest_node_so_far) for n in self.connections[shortest_node_so_far]: if self.shortest_path_distance[shortest_node_so_far] + n[1] < self.shortest_path_distance[n[0]] and len(self.shortest_path[shortest_node_so_far]+[n[0]])-1 <= max_path_stop: self.shortest_path_distance[n[0]]=self.shortest_path_distance[shortest_node_so_far] + n[1] self.shortest_path[n[0]]=self.shortest_path[shortest_node_so_far]+[n[0]] if __name__ == "__main__": g = Graph() edges = [(1,2,7),(1,3,9),(1,6,14),(2,3,10),(3,6,2),(5,6,9),(5,4,6),(3,4,11),(2,4,15)] for e in edges: g.add_edge(e) g.calculate_shortest_path(1,2) print g.shortest_path print g.shortest_path_distance 2 por alguna razón: Por eso no podemos tener cosas bonitas

Original en ingles

I'm trying to figure out how to nicely write a Winforms app that reports the progress of completing a long task onto the main form's controls without causing Cross-thread op exceptions and such. So far I've come up with this scheme which at least works, but doesn't look very nice:

Progress<MyProgress> progress = new Progress<MyProgress>(); private void Form1_Load(object sender, EventArgs e)  {     progress.ProgressChanged += (x, y) =>         Invoke(new Action(() => { toolStripStatusLabel1.Text = y.text;                                   toolStripProgressBar1.Value = y.percentage; })); }  bool DoVeryHeavyStuff(IProgress<MyProgress> progress) {     progress.Report(new MyProgress() { percentage = 0, text = "Doing heavy stuffxe2x80xa6" }); }  async void button_doHeavyStuff_Click(object sender, EventArgs e) {     bool success = await Task.Run(() => DoVeryHeavyStuff(progress)); } 

As you can see, the right part of the progress.ProgressChanged += looks overly complex. Isn't there a way it can be written more simply?

One thing I could think of is creating a separate method, but that wouldn't help much, as it would still have to be referred to in that line.

progress.ProgressChanged += (x, y) =>     Invoke(new Action(() => progress_ProgressChanged(x, y)));  void progress_ProgressChanged(object sender, MyProgress e)     {         toolStripStatusLabel1.Text = e.text;         toolStripProgressBar1.Value = e.percentage;     } 

I managed to break it apart like this, but it looks even worse:

progress.ProgressChanged += (x, y) => ReportProgressA(x, y); void ReportProgressA(object sender, MyProgress e) {     Invoke(ReportProgressB(sender, e)); } Action ReportProgressB(object sender, MyProgress e) {     return () => progress_ProgressChanged(sender, e); } 

Invoke seems to be essential to avoiding cross-thread exceptions, but it requires a delegate as a parameter. I don't have much experience with delegates, so I don't know how to simplify the Action initialization code.

It looks like I can't just drop the explicit cast to Action for some reason: this is why we can't have nice things

        
 
 

Lista de respuestas

3
 
vote

Lo que ha proporcionado es una expresión de lambda.

El método de invocaciones lleva a un delegado como un argumento. Antes de explicar lo que es un delegado, la respuesta simple a su pregunta es proporcionar uno de los tipos de delegados predefinidos visited3 o visited4 . Estos pueden parecer mágicos, pero confían en mí, son conceptos súper simples una vez que envuelves tu cabeza alrededor de ellos.

visited5 La acción no toma parámetros y devuelve el vacío

visited6 visited7 devuelve visited8 y no tiene parámetros.

visited9 y shortest_path0 son simplemente delegados predefinidos. shortest_path1 se define así:

shortest_path2

¿Qué es un delegado?

Un delegado simple y simple es una forma de describir una firma de método: es decir, ¿qué devuelve el método (en su caso) y qué argumentos (si corresponde) se necesita?

Otra forma de pensar en esto es cuando termino haciendo mi trabajo, siempre notifico a alguien a que les hagan saber el estado de los objetivos alcanzados. Para que este proceso sea flexible, le permito especificar esa unidad de trabajo. Invocaré el método personalizado y lo enviaré el estado de mi trabajo. Para que esto suceda, obviamente, necesito establecer algunas reglas generales básicas, las reglas son que el método que invoco necesita necesidad de tomar una cadena (el estado que le envío) y devolverme una respuesta (tal vez esa respuesta sea "Ok, vaya a casa" o etc.).

La belleza de especificar solo la firma del método es que puede invocar su propio método personalizado para ser invocado (como lo desea arriba) o podría especificar cualquier método que coincida con la firma. En nuestra cadena de casos, la cadena fuera, coincidiría con shortest_path3 (solo el nombre). Obviamente, en nuestro escenario, puedo estar confundido por la respuesta, pero esta forma de programación le permite conectar diferentes implementaciones. Una implementación podría ser que le notifique por teléfono, o correo electrónico o mensaje de texto, etc.

Dependiendo de su caso de uso, puede devolver el vacío del método porque simplemente desea que se inicie un correo electrónico una vez que invoque internamente el método que me ha dado.

Usted ve una gran cantidad de esta programación en la cosa como JavaScript, es asíncrono, le devuelve el control de inmediato y le permite especificar una función de devolución de llamada, esencialmente un delegado que debe invocarse una vez que se haga.

 

What you've provided is a lambda expression.

The Invoke method takes a delegate as an argument. Before I explain what a delegate is, the simple answer to your question is provide one of the predefined delegate types Action or Func. These may seem like magic, but trust me, they are super simple concepts once you wrap your head around them.

Invoke(new Action(() => {...})) Action takes no parameters and returns void

Invoke(new Func<bool>(() => { return false; })); Func<T> returns T and has no parameters.

Action and Func<T,...> are simply predefined delegates. Action is defined like so:

public delegate void Action();

What is a delegate?

A delegate plain and simple is a way to describe a method signature - that is, what does the method return (if anything) and what arguments (if any) does it take.

Another way to think about this is when I'm done doing my work I always notify someone to let them know the status of goals achieved. To make this process flexible I allow you to specify that unit of work. I will invoke the custom method and send it the status of my work. For this to happen obviously I need to set some general ground rules, the rules being that the method I invoke needs to take a string (the status I send you) and return a response to me (maybe that response is "ok go home" or etc).

The beauty of specifying only the method signature is that you can make your own custom method to be invoked (as you want to above) or you could specify any method that matches the signature. In our case string in, string out would match String.Reverse (just the name). Obviously in our scenario I may be confused by the response, but this way of programming allows you to plug in different implementations. One implementation could be that I notify you via phone call, or email, or text message etc.

Depending on your use case you might return void from the method because you just want an email to be kicked off once I internally invoke the method you've given to me.

You see a lot of this programming in thing like JavaScript, it is asynchronous, it returns control back to you right away and allows you to specify a callback function, essentially a delegate that should be invoked once it's done.

 
 
0
 
vote

en su ventana o clase de ventana de base, implemente un método como este:

  shortest_path4  

Luego, cuando desea actualizar un elemento GUI, haga esto:

  shortest_path5  
 

On your window or base window class, implement a method like this:

    protected virtual void InvokeIfRequired(Action action)     {         if (this.InvokeRequired)         {             this.Invoke(action);         }         else         {             action();         }     }  

Then when you want to update a GUI element, do this:

    this.InvokeIfRequired(() => textBox.Text = "Some result");     // or a block     this.InvoveIfRequired(() => {         textBoxt2.Text = "Some result 2";         textBoxt3.Text = "Some result 3";     }); 
 
 

Relacionados problema

7  ASYNC / AWAIT EN PARALLO  ( Async await in parallel foreach ) 
Tengo un 99887766555443317 : ctypedef8 La parte importante aquí es el método ctypedef9 . Tengo algunas dudas aquí: ¿Está bien tener un método 99...

6  Uso y comprensión de ASYNC / AWAIT en .NET 4.5 +  ( Use and understanding of async await in net 4 5 ) 
Estoy a punto de embarcarse en un trabajo masivo de múltiples hilos de un motor. Podría usar el TPL de los cuales soy muy familiar, pero me gustaría aprovecha...

8  Reintento de lazo para solicitudes de HTTP asíncrono  ( Retry loop for asynchronous http requests ) 
Tengo un método que necesita poner datos a una API web. A veces, la conexión falla, así que necesitaba una forma de hacer reintentos, pero si los reintentos f...

3  Mini HTTPCLIENT JSON POST POR PARÁMETRO DE ACCIÓN  ( Mini httpclient json post by action parameter ) 
Esta es una implementación de HTTPClient JSON POST POST POR PARÁMETRO. lógica: Es muy conveniente pasar la URL y el objeto (convertido automáticamente...

3  JavaScript que elimina todo dentro de una carpeta en box.com  ( Javascript that deletes everything inside a folder on box com ) 
Acabo de terminar un script simple para el nodo que eliminará todas las carpetas y archivos dentro de un ID de carpeta específico a través de la API del cuadr...

10  Enviando notificaciones con canales Django  ( Sending notifications with django channels ) 
Tengo proyecto en Django, use los canales Django. Utilizo el canal Django para enviar notificaciones a los usuarios que se suscriben a los cambios de artículo...

12  Pila de intercambio WebSockets Wrapper  ( Stack exchange websockets wrapper ) 
He estado escribiendo una pequeña biblioteca que permite una fácil consulta de las bandas de intercambio de pila. Voy a agregar un enum para reemplazar el...

7  Cola tamponada para el registro  ( Buffered queue for logging ) 
Me gustaría usar una cola amortiguada para registrar a través de una WEBAPI que maneja múltiples aplicaciones. Este ayudante debe reducir el bloqueo que se pr...

8  Administración de la configuración de la aplicación de Python en un almacén de valor clave  ( Managing python application configuration in a key value store ) 
Para un proyecto en el que estamos trabajando, necesitamos un lugar central para almacenar las configuraciones para varias aplicaciones (son todos los servici...

4  Inyectar un DBContext con una dependencia constructora de ASYNC  ( Injecting a dbcontext with an async constructor dependency ) 
El objetivo es construir un DbContext con una conexión que utiliza un token de acceso. El token de acceso se adquiere con ADAL (Biblioteca de autenticación ...




© 2022 respuesta.top Reservados todos los derechos. Centro de preguntas y respuestas reservados todos los derechos