Pregunta

Estoy usando el patrón Model-View-Presenter en un proyecto de WinForms y un problema (entre muchos) que tengo es cuando el formulario le dice al presentador que haga algo y luego no reacciona mientras el presentador pasa a hazlo. Afortunadamente, en mi proyecto no tengo problemas para hacer que todas las llamadas del presentador sean asíncronas. La pregunta es cómo hacerlo exactamente.

¿Debería cada llamada de presentador estar envuelta en una nueva creación de hilo? *

new Thread(()=>_presenter.DoSomething()).Start();

¿Cuáles son las mejores prácticas aquí? ¿Qué pasa si el usuario presiona un " Abortar lo que estás haciendo? ¿botón? ¿Cómo aborto con gracia?

. * Siendo realistas, probablemente usaría algún tipo de proxy en el presentador para hacer esto en lugar de poner la creación del hilo en el WinForm

¿Fue útil?

Solución

Solo puedo afirmar que he pensado en esto (antes de leer su pregunta;). Primero manipularía los lugares donde esto realmente importa; por ejemplo, el punto de acceso de acceso a la base de datos. Si hay un lugar que no debe ejecutarse en la " UI " contexto (puede guardarlo desde http: // msdn .microsoft.com / en-us / library / system.threading.synchronizationcontext.current.aspx en el subproceso de la interfaz de usuario y luego se compara más tarde con el contexto de sincronización que no es de la interfaz de usuario) y luego Debug.BitchAndMoan () al respecto. Cualquier cálculo más largo (que '' debería '' estar claramente separado en sus propios colectores, correcto;) debería afirmar eso.

Supongo que al menos debería hacer que el tipo de ejecución de la función de presentador sea configurable mediante un atributo que luego es obedecido por el proxy. (solo en caso de que quiera hacer algo en serie).

Cancelar una tarea es en realidad un problema del presentador, pero debe tener un objeto de referencia que le indique qué desea detener. Si sigue el camino del proxy, podría recoger los hilos creados en la lista de tareas con IAsyncResult, pero aún es un problema decidir cuál se supone que se cancelará si se permite que se llame la misma acción varias veces en paralelo. Por lo tanto, debe proporcionar a la tarea un nombre específico de llamada adecuado cuando la inicie; lo que implica demasiada lógica en el lado de Vista - > El presentador probablemente debería preguntarle a View para preguntarle al usuario cuál de las tareas debe eliminarse.

Mi experiencia es que esto generalmente se soluciona mediante el uso de eventos (estilo SCSF). Si lo hiciera desde cero, iría por el proxy ya que SCSF ha sido un dolor en tantas formas que dudo de la cordura de sus diseñadores.

Otros consejos

Normalmente coloco cualquier acción que pueda (de manera realista) tomar más de un segundo o dos en una tarea separada, algo así como:

public interface ITask
{
    void ExecuteTask (ITaskExecutionContext context);
    void AfterSuccess(ITaskExecutionContext context);
    void AfterFailure(ITaskExecutionContext context);
    void AfterAbortion(ITaskExecutionContext context);
}

También tengo una abstracción para ejecutar tales tareas:

public interface ITaskExecutor : IDisposable
{
    void BeginTask(ITask task);
    void TellTaskToStop();
}

Una de las implementaciones de este ITaskExecutor está utilizando el BackgroundWorker :

public class BackgroundTaskExecutor : ITaskExecutor
{
    public void BeginTask(ITask task)
    {
        this.task = task;
        worker = new BackgroundWorker ();
        worker.DoWork += WorkerDoWork;
        worker.RunWorkerCompleted += WorkerRunWorkerCompleted;
        worker.WorkerSupportsCancellation = true;

        worker.RunWorkerAsync();
    }

    ...
}

Confío mucho en la inyección de dependencia y la IoC para conectar las cosas. En el presentador, simplemente llamo algo como:

GoAndDontReturnUntilYouBringMeALotOfMoneyTask task = new GoAndDontReturnUntilYouBringMeALotOfMoneyTask(parameters);
taskExecutor.BeginTask(task);

Los botones Cancelar / abortar se conectan para que le indiquen al ejecutor / tarea que cancele.

En realidad es un poco más complejo que el presentado aquí, pero esta es la idea general.

¿Por qué no hacer que el patrón proxy que usa acepte un par de devoluciones de llamadas para devolver los resultados o cancelar?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top