Domanda

Sto usando il modello Model-View-Presenter in un progetto WinForms e un problema (tra i tanti) che sto riscontrando è quando il modulo dice al presentatore di fare qualcosa e quindi non è reattivo mentre il presentatore va a fallo. Fortunatamente nel mio progetto non ho problemi a rendere asincrone tutte le chiamate del presentatore, la domanda è: come si fa esattamente?

Ogni chiamata del relatore dovrebbe essere semplicemente racchiusa in una nuova creazione di thread? *

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

Quali sono le migliori pratiche qui? Che cosa succede se l'utente preme " Annulla ciò che stai facendo " pulsante? Come posso interrompere con grazia?

. * Realisticamente probabilmente userei una sorta di proxy sul presentatore per fare questo invece di mettere la creazione del thread in WinForm

È stato utile?

Soluzione

Posso solo affermare di averci pensato (prima di leggere la tua domanda;). Prima di tutto truccerei i posti in cui questo conta davvero; ad esempio il chokepoint di accesso al DB. Se è presente un posto che non deve essere eseguito nell'interfaccia utente "quotata" contesto (puoi salvarlo da http: // msdn .microsoft.com / it-it / library / system.threading.synchronizationcontext.current.aspx nel thread dell'interfaccia utente e quindi confrontare successivamente con il contesto di sincronizzazione non dell'interfaccia utente) quindi Debug.BitchAndMoan (). Ulteriori calcoli (che "dovrebbero" essere chiaramente separati nelle loro varie varietà, giusto;) dovrebbero affermarlo.

Suppongo che dovresti almeno rendere il tipo di esecuzione della funzione presentatore configurabile tramite l'attributo che viene poi obbedito dal proxy. (nel caso in cui desideri qualcosa fatto in serie).

L'annullamento di un'attività è in realtà un problema del relatore, ma è necessario disporre di un oggetto di riferimento che indichi ciò che si desidera interrompere. Se si procede in modo proxy, è possibile raccogliere i thread creati nell'elenco delle attività con IAsyncResult's, ma è ancora un problema decidere quale dovrebbe essere annullato se è possibile chiamare la stessa azione più volte in parallelo. Quindi è necessario fornire all'attività un nome specifico per la chiamata adatto quando lo si avvia; che implica troppa logica nella vista laterale - > Il relatore dovrebbe probabilmente chiedere a View di chiedere all'utente quale delle attività deve essere eliminata.

La mia esperienza è che questo di solito viene semplicemente risolto usando eventi (stile SCSF). Se lo facessi da zero, farei la via del proxy poiché SCSF è stato un dolore in così tanti modi che dubito della sanità mentale dei suoi progettisti.

Altri suggerimenti

Di solito metto qualsiasi azione che può (realisticamente) prendere più di un secondo o due in un compito separato, qualcosa come:

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

Ho anche un'astrazione per eseguire tali compiti:

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

Una delle implementazioni di questo ITaskExecutor sta usando il 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();
    }

    ...
}

Faccio fortemente affidamento sull'iniezione delle dipendenze e sull'IoC per collegare le cose. Nel presentatore poi chiamo semplicemente qualcosa del tipo:

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

I pulsanti Annulla / Annulla vengono quindi cablati in modo da indicare all'esecutore / attività da interrompere.

In realtà è un po 'più complesso di quanto presentato qui, ma questa è l'idea generale.

Perché non fare in modo che il modello proxy utilizzato accetti un paio di richiamate per restituire i risultati o interrompere?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top