Как отправлять обновления о прогрессе из класса бизнес / модель? - PullRequest
9 голосов
/ 25 января 2011

Допустим, у нас есть приложение с многоуровневой архитектурой. На представлении мы используем MVC или MVVM. Модель рассматривается как домен, она имеет хорошую часть бизнес-логики.

Теперь, допустим, у нас в модели есть метод, который занимает некоторое время. Сложный расчет или обработка, которая должна быть сделана для каждого элемента объекта, например.

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

Как бы ты это сделал? Как отправить из модели информацию о ходе процесса и как подключить контроллер или ViewModel, чтобы он обновлял прогресс?

Ответы [ 5 ]

6 голосов
/ 28 января 2011

Я часто реализую это следующим образом. Процесс моего бизнес-уровня, который занимает много времени, периодически вызывает события, чтобы показать, что он достигает определенных «вех». Вы сами решаете, какие вехи будут сигнализировать через события и сколько их. Если ваш трудоемкий процесс представляет собой простой цикл, вы можете, например, выбрать повторение одного и того же события снова и снова через каждые 10% элементов цикла. Если это процесс с различными фазами, вы можете инициировать другое событие, когда каждая фаза завершена.

Теперь ваш уровень представления подписывается на эти события и, соответственно, действует, обновляя индикатор выполнения, текст или что-либо еще.

Этот механизм хорош, потому что:

  1. Бизнес-уровень остается независимым от того, что может происходить на уровне представления.
  2. Это легко расширить для двунаправленной связи. Вы можете легко изменить события, чтобы уровень представления (или любой другой подписчик) мог вернуть флаг отмены, чтобы бизнес-уровень знал, что длительный процесс должен быть отменен.
  3. Допускается синхронная или асинхронная работа. То есть вы можете использовать его для блокирования вызовов (т. Е. Ваш презентационный и бизнес-уровень совместно используют один и тот же поток) или неблокирующих вызовов (т. Е. Ваш бизнес-уровень использует фоновый рабочий поток). Класс System.ComponentModel.BackgroundWorker может использоваться в последнем случае, но это не слишком хорошо, если вы хотите вызвать несколько типов событий.

Надеюсь, это поможет.

2 голосов
/ 29 января 2011

Я бы порекомендовал взглянуть на класс BackgroundWorker, предоставленный в пространстве имен System.ComponentModel.

Фоновый рабочий предоставляет необходимые методычтобы выполнить интенсивную работу в отдельном потоке и получать обновления статуса о ее ходе (через ReportProgress, ProgressChanged и RunWorkerCompleted).

Я лично лично экспериментировал с использованием BackgroundWorkerв веб-среде для запуска запланированных задач.Я решил опубликовать работу, которую я проделал до сих пор на codeplex.Я чувствую, что дух моего кода может быть полезен для вашей ситуации. Проект кодекса «Web Scheduled Task Framework» .

Если вы решите загрузить проект, вы увидите, как я использую класс BackgroundWorker в классе ScheduledTaskRunner.Моя реализация не привязывает события прогресса к работнику, но это было бы очень легко сделать.Кроме того, моя текущая реализация фокусируется на выполнении задачи в заданном интервале, но изменение ее так, чтобы она была скорее очередью обработки «по требованию», не было бы очень сложным.Я могу даже добавить это как особенность теперь, когда я об этом думаю:)

Предполагая, что вы следовали подходу моего кода выше, было бы легко создать действие на вашем контроллере, который был запущен, будет проверятьсписок «заданий» (или интересующих вас конкретных заданий) и сообщайте информацию в виде ActionResult.Настройте некоторый javascript для опроса действия в указанный интервал, и вы будете иметь успехи!

Удачи и дайте мне знать, если у вас есть какие-либо вопросы по поводу моего кода.

1 голос
/ 31 января 2011

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

Тогда подход ViewModel Model View может подойти: http://en.wikipedia.org/wiki/Model_View_ViewModel

Когда вычисление выполнено, вы бросаете события, в которых достигнут прогресс.

Эти события перехватываются в ViewModel, и количество прогресса обновляется.

Затем представление обновляется из-за привязки данных между ViewModel и представлением (шаблон наблюдателя)

1 голос
/ 29 января 2011

Я применил следующий подход к подобному случаю.Эта точка зрения имеет действие, которое может занять много времени, и я хотел бы периодически показывать прогресс.Длительное действие перенесено в другой класс, рабочий.Некоторые действия пользователя инициируют вызов DoSomething в TestViewModel.

TestView.xaml

...
<!-- Progress bar -->
<ProgressBar Visibility="Visible" Height="10" Value="{Binding SomeValue}"/>
...

TestViewModel.cs расширяет BaseViewModel, BaseViewModel просто реализует INotifyPropertyChanged

...
private void DoSomething(){
    Worker worker = new Worker();
    worker.ProgressChanged += new EventHandler<WorkerEventArgs>(OnProgressChanged);
    worker.Start();
}

private void OnProgressChanged(object sender, WorkerEventArgs args){
    SomeValue = args.Progress;
}

private const String SomeValuePropertyName = "SomeValue";
private double someValue;
public double SomeValue
{
    get
    {
        return someValue;
    }
    set
    {
        if (someValue == value)
        {
            return;
        }
        someValue = value;
        NotifyPropertyChanged(SomeValuePropertyName);
    }
}
...

Worker.cs

...
public event EventHandler<WorkerEventArgs> ProgressChanged;
public void Start(){
    //This will take a long time. Periodically call NotifyProgress
}

private void NotifyProgress()
{
    if (ProgressChanged != null)
    {
        double progress = ...; //calculate progress
        ProgressChanged(this, new WorkerEventArgs(progress));
    }
}
...

WorkerEventArgs.cs

public class WorkerEventArgs : EventArgs
{
    public double Progress { get; private set; }

    public WorkerEventArgs(double progress)
    {
        Progress = progress;
    }
}
0 голосов
/ 26 января 2011

Вам понадобится изучить шаблон наблюдателя (http://en.wikipedia.org/wiki/Observer_pattern). Это довольно распространенный подход для настольных приложений. Он немного сложнее для Интернета. Возможно, вы также захотите заглянуть в Comet [http://en.wikipedia.org/wiki/Comet_(programming)], чтобы увидеть, как это делается дляWeb.

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