Лучшие практики для асинхронных вызовов в MVP с WinForms - PullRequest
8 голосов
/ 06 мая 2009

Я использую шаблон Model-View-Presenter в проекте WinForms, и одна проблема (среди многих), с которой я сталкиваюсь, заключается в том, что форма говорит докладчику сделать что-то, а затем перестает реагировать, когда докладчик переходит к сделай это. К счастью, в моем проекте у меня нет проблем с асинхронным вызовом всех докладчиков, вопрос в том, как именно это сделать?

Должен ли каждый вызов докладчика быть обернут в создание нового потока? *

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

Каковы лучшие практики здесь? Что делать, если пользователь нажимает кнопку «Прервать то, что вы делаете»? Как мне прервать изящно?

. * Реально, я бы просто использовал прокси на презентере, чтобы сделать это, а не помещал создание потоков в WinForm

Ответы [ 3 ]

5 голосов
/ 06 сентября 2010

Я обычно помещаю любое действие, которое (реально) может занять больше секунды или две, в отдельную задачу, что-то вроде:

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

У меня также есть абстракция для запуска таких задач:

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

Одна из реализаций этого ITaskExecutor использует 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();
    }

    ...
}

Я сильно полагаюсь на внедрение зависимостей и IoC для объединения вещей. Тогда в докладчике я просто называю что-то вроде:

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

Затем кнопки «Отмена / Отмена» подключаются так, что они сообщают исполнителю / задаче об отмене.

Это на самом деле немного сложнее, чем представлено здесь, но это общая идея.

2 голосов
/ 06 мая 2009

Я могу только утверждать, что я думал об этом (до прочтения вашего вопроса;). Сначала я бы подстроил места, где это действительно имеет значение; например, точка доступа к БД. Если есть место, которое не должно выполняться в контексте «пользовательского интерфейса» (вы можете сохранить его из http://msdn.microsoft.com/en-us/library/system.threading.synchronizationcontext.current.aspx в потоке пользовательского интерфейса, а затем сравнить его с контекстом синхронизации не из пользовательского интерфейса), тогда выполните Debug.BitchAndMoan () об этом. , Любые более длинные вычисления (которые «должны» быть четко разделены в своих собственных многообразиях, верно;) должны утверждать, что.

Полагаю, вам следует, по крайней мере, сделать тип выполнения функции презентатора настраиваемым через атрибут, которому затем подчиняется прокси. (на всякий случай, если вы хотите, чтобы что-то было сделано серийно).

Отмена задачи на самом деле является проблемой докладчика, но у вас должен быть эталонный объект, который сообщает, что вы хотите остановить. Если вы пойдете по прокси-серверу, вы можете забрать созданные потоки в список задач с помощью IAsyncResult, но все еще остается проблема решить, какой из них должен быть отменен, если одно и то же действие разрешено вызывать несколько раз параллельно. Таким образом, вы должны предоставить заданию подходящее имя для конкретного вызова при запуске; что подразумевает слишком много логики в сторону View -> Presenter, вероятно, должен попросить View спросить пользователя, какая из задач должна быть выполнена.

По моему опыту, это обычно обходится с помощью событий (стиль SCSF). Если бы я делал это с нуля, я бы пошел по доверенному пути, поскольку SCSF причинял столько боли, что я сомневаюсь в здравом уме его дизайнеров.

0 голосов
/ 06 мая 2009

Почему бы не сделать так, чтобы используемый вами прокси-шаблон принимал пару обратных вызовов для возврата результатов или отмены?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...