mvp асинхронный прогресс winforms

#c# #winforms #mvp

#c# #winforms #mvp

Вопрос:

я реализовал простой ProgressPresenter

 public interface IProgressView
{
    string Status { set; }
    void SetProgress(int percentageDone);

    void Display();
    void Close();

    event Action Closing;
}

class ProgressPresenter
{
    private IProgressView m_view;
    private ILongRunningTask m_task;
    private bool m_completed;

    public Progress(IProgressView view)
    {
        m_view = view;
    }

    public virtual void Display(ILongRunningTask task, string taskName)
    {
        m_task = task;

        m_view.Status = taskName " is running";

        m_view.Closing  = OnClosing;
        task.ProgressChanged  = UpdateProgress;
        task.Completed  = Completed;

        task.StartAsync();

        m_view.Display();

        m_view.Closing -= OnClosing;
        task.ProgressChanged -= UpdateProgress;
        task.Completed -= Completed;
    }

    protected virtual void UpdateProgress(object sender, ProgessEventArgs e)
    {
        m_view.SetProgress(e.AlreadyDone * 100 / e.Total);
    }

    protected virtual void Completed()
    {
        m_completed = true;
        m_view.Status = "Completed";
        m_view.Close();
    }

    private virtual void OnClosing()
    {
        if (!m_completed) m_downloader.Cancel();
    }
}
  

Моя проблема в том, что задача выполняется в другом потоке, и каждый вызов представления (реализованный как Form ) выдает ошибку. Должен ли я обернуть каждый метод в форму, подобную

 public string Status
{
    set { Invoke(new Action(() => progressLabel.Text = value)); }
}
  

на всякий случай, если его можно вызвать из другого потока? или в Presenter есть недостатки?

Приветствуются любые советы

Ответ №1:

Да, вы должны это сделать. Я не знаю, какие другие библиотеки вы используете, но, вероятно, было бы неплохо добавить аспект ко всем вашим представлениям, чтобы сделать это за вас.

Также, возможно, стоило бы добавить пару удобных методов в базовом представлении; Например. У меня есть эти:

     public void Invoke(Action action)
    {
        if (_control.InvokeRequired)
        {
            _control.Invoke(action);
            return;
        }

        action();
    }

    public T Invoke<T>(Func<T> action)
    {
        if (_control.InvokeRequired)
            return (T)_control.Invoke(action);

        return action();
    }
  

пример реализации aspect смотрите здесь

Комментарии:

1. спасибо за ответ. оба варианта довольно полезны. ATM Я не хочу зависимости от реального IOC, поэтому я создал свой собственный, очень простой, поэтому сейчас я выбираю второй вариант

2. Вы можете использовать Postsharp в качестве альтернативы аспектам, подобным прокси!