Обобщение интерфейса с индикатором выполнения в графическом интерфейсе - PullRequest
0 голосов
/ 25 февраля 2010

Я работаю над приложением, которое имеет основную форму со строкой состояния внизу. Строка состояния содержит ProgressBar и метку, которую я хочу использовать, чтобы показать пользователю текущий прогресс в выполнении некоторой работы. Строка состояния также содержит метку, которую я хочу использовать как нажимаемую кнопку «Отмена».

Раньше я создавал асинхронные интерфейсы, но они всегда основывались на одном действии и использовании фонового работника. Но в этой новой программе есть ряд различных действий, которые пользователь может выполнить, для которых я хочу использовать эту же строку состояния, чтобы показать прогресс. Поэтому я пытаюсь найти способ обобщить и стандартизировать интерфейс к этим элементам управления отчетами о прогрессе в строке состояния.

В некоторых случаях асинхронные процессы создаются с использованием BackGroundWorker, но в других случаях мне нужно создать управление вторичными потоками напрямую.

Вот некоторый наполовину законченный скелетный код того, о чем я думал:

public partial class MyForm: System.Windows.Forms.Form
{
    ...SNIP...

    private void WorkProgressChanged(Object sender, EventArgs args)
    {
        ProgressChangedEventArgs backgroundWorkerArgs = args as ProgressChangedEventArgs;
        ProgressReport formReport = args as ProgressReport; //my own custom progress report class


       //tries to cast args to a Background worker args
        if (backgroundWorkerArgs != null)
        {
            // update UI based on backgroundWorkerArgs

        }
        else if (formReport != null)
        {
            // update UI basd on formReport

        }

        else 
        {
            //couldn't figure out what kind of progress report was sent
            //update UI based on args.ToString();

        }

    }


    private void cancelButtonToolStripLabel_Click(object sender, EventArgs e)
    {
        //calls cancel method of current processing
        if (this._currentWorkCancelAction != null)
        {
            _currentWorkCancelAction(); //envoke cancel requet
            cancelButtonToolStripLabel.Text = "Canceling"; //shows user that cancel request was made
            _currentWorkCancelAction = null; //disaccociates cancel button to prevent user from canceling twice
        }
    }


    private void WorkProcessCompleted(Object sender, EventArgs args)
    { 
        //Reset cancel button
        cancelButtonToolStripLabel.Text = "Cancel";
        cancelButtonToolStripLabel.Visible = false;

        //resets the status label and progress bar
        statusToolStripLabel.Text = "";
        toolStripProgressBar.Value = 0;


    }

....SNIP

}

Таким образом, строка состояния обновляется путем подписки `WorkProgressChanged (Object sender, EventArgs args) на некоторое событие 'и в конечном итоге сбрасывается, когда' WorkProcessCompleted (Object sender, EventArgs args) 'вызывается даже после завершения. Моя метка отмены (кнопка) также должна быть связана, а затем диссоциирована с помощью метода делегата, который будет запрашивать отмену любой выполняемой в данный момент работы.

Таким образом, каждый раз, когда работа выполняется, должна происходить куча вещей. Подписки на события добавляются / удаляются, ссылки на делегаты изменяются и т. Д. И т. Д. Итак, я начал задаваться вопросом, можно ли каким-либо образом инкапсулировать все эти действия в один или два метода многократного использования вместо написания дублирующего кода для каждого действия, которое может выполнить место.

Метод InitWorkProcess() ниже показывает, как я думаю, это может работать. Хотя я почти уверен, что это неправильный способ использования класса EventDescriptor. Я не мог найти какой-либо другой способ ссылаться на событие как параметр метода. Может быть, это невозможно?

    public void InitWorkProcess(EventDescriptor workProgressChangedEvent, EventDescriptor workCompletedEvent, System.Action requestCancel)
    { 
        //subscribe to progress changed
        workProgressChangedEvent.AddEventHandler(this, this.WorkProgressChanged);
        this._workProgressChangedEvent = workProgressChangedEvent;

        //subscribe to process completed
        workCompletedEvent.AddEventHandler(this, this.WorkProcessCompleted);
        this._workCompletedEvent = workCompletedEvent;


        //enable cancel button
        if (requestCancel != null)
        {
            cancelButtonToolStripLabel.Visible = true;
            this._currentWorkCancelAction = requestCancel;
        }
    }

... и я бы изменил метод обработки событий WorkProgressComplete, чтобы отписать отношения событий после завершения работы.

    private void WorkProcessCompleted(Object sender, EventArgs args)
    { 
        //Reset cancel button
        cancelButtonToolStripLabel.Text = "Cancel";
        cancelButtonToolStripLabel.Visible = false;

        //resets the status label and progress bar
        statusToolStripLabel.Text = "";
        toolStripProgressBar.Value = 0;


        //unsubscribes WorkProcessCompleted() and WorkProgressChanged() methods
        this._workCompletedEvent.RemoveEventHandler(this, this._workCompletedEvent);
        this._workCompletedEvent = null;

        this._workProgressChangedEvent.RemoveEventHandler(this, this._workProgressChangedEvent);
        this._workProgressChangedEvent = null;
    }

У кого-нибудь есть предложения, как мне это настроить? Должен ли я просто забыть о методе InitWorkProcess() и вместо этого добавить / удалить все отношения событие / делегат отдельно для каждого действия? Или есть лучший способ полностью?

Ответы [ 2 ]

1 голос
/ 21 апреля 2011

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

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

«Проводка» должна быть в общем родительском элементе управления, отображая события в изменения на панели прогресса через открытый интерфейс.

0 голосов
/ 25 февраля 2010

Почему бы просто не использовать ProgressChangedEventArgs из вашего пользовательского потока, а также использовать общий объект события любого фонового работника ... вместо того, чтобы пытаться работать с несколькими типами объектов отчетов о прогрессе?

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