Лучшие практики для асинхронных вызовов в MVP с WinForms

StackOverflow https://stackoverflow.com/questions/831051

Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

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

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

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

Другие советы

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

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);

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top