Может ли Invoke выполнить код основного потока пользовательского интерфейса, который выдает исключение? - PullRequest
0 голосов
/ 11 февраля 2010

В моем коде ниже я использую объекты Process для выполнения серии командных файлов DOS. Я сокращаю список скриптов для примера.

Последующие (1+) сценарии выполняются через обработчик событий (вместо цикла for). Таким образом, каждый последующий скрипт выполняется ТОЛЬКО после завершения предыдущего. Теперь по какой-то причине, когда я выполняю второй сценарий, я не могу получить пойманное исключение для заполнения строки состояния сообщением об ошибке.

Я проверяю, когда в файле app-config вводятся недопустимые имена сценариев, и я подозреваю Я неправильно использую делегатов. Мой анонимный делегат состоит из комбинации «нового кода» и существующих методов класса. Вот что я считает неправильным; Если бы вы все могли подтолкнуть меня к тому, почему я был бы признателен;)

ПРИМЕЧАНИЕ: this.copy_scripts [] создан из разбиения: "goodname.bat, nosuchscript.bat"

private void copybutton_Click(object sender, EventArgs e)
    {

        InitializeBar();

        this.nbr_of_copy_exits_ = 0;
        this.RunCopyScript(this.nbr_of_copy_exits_);
        return;
    }

private void RunCopyScript(Int32 CopyScriptIdx)
    {
        Process proc = null;
        try
        {
            proc = this.ObtainProcess(this.client_dest_dir_ + this.copy_scripts_[CopyScriptIdx]);
            proc.EnableRaisingEvents = true;
            proc.Exited += new EventHandler(CopyExited);
            proc.Start();
            this.progressBar.Value = ProgressInPercent(this.copy_scripts_.Count(), CopyScriptIdx);
        }
        catch (Exception ex)
        {
            this.UpdateControl(this.toolStripStatusLabel1, "Error involving " + this.copy_scripts_[CopyScriptIdx] + ": " + ex.Message);
            this.copybutton.BackColor = Color.Red;
        }
        return;
    }

void CopyExited(object sender, EventArgs e)
    {
        System.Diagnostics.Process senderProcess
            = sender as System.Diagnostics.Process;

        this.Invoke((MethodInvoker)delegate
        {
            if (++this.nbr_of_copy_exits_ == this.copy_scripts_.Count())
            {
                this.UpdateControl(this.toolStripStatusLabel1, "Copying COMPLETE.");
                this.progressBar.Value = 0;
            }
            else
            {
                this.RunCopyScript(this.nbr_of_copy_exits_);
            }
        });
    }

        private void UpdateControl(ToolStripStatusLabel tssl, String text)
    {
        tssl.Text = text;
        tssl.Refresh();
    }

1 Ответ

1 голос
/ 13 февраля 2010

Я думаю, что вместо использования события для настройки и продолжения цикла, я бы создал асинхронный делегат с методом обратного вызова. Когда процесс завершится, вы просто перезвоните на RunCopyScript(...) снова. Взгляните на делегатов на MSDN и асинхронное программирование . Я уверен, что у кого-то будет способ сделать это с Action, я просто не знаю этого достаточно хорошо, чтобы привести вам пример.

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

Хорошо, вот что у меня есть - для чего оно стоит. Я считаю это довольно точно. Я не ожидал, что он будет скомпилирован из коробки, так как у меня нет всех файлов, путей и т. Д. Для правильного запуска процессов. А установка имитированных командных файлов на Start() a Process потребует немного больше работы. Я полагаю, что вы должны быть в состоянии работать с этим и иметь что-то более близкое к тому, что вы хотите, если сделать перекрестную ссылку со ссылкой, которую я предоставил выше.

Я также прокомментировал некоторые строки кода, которые не были бы нужны, я переехал или не был распознан. Кроме того, я ничего не делал с вашим текущим try/catch блоком.

// same signature as the method to be called asynchronously
delegate void RunScript(Int32 scriptIdx);

// declare IAsyncResult
IAsyncResult result;

Process proc = null;

private void copybutton_Click(object sender , EventArgs e)
{
    InitializeBar();

    nbr_of_copy_exits_ = 0;
    //this.RunCopyScript(this.nbr_of_copy_exits_);
    RunScript start = new RunScript(RunCopyScript);

    result = start.BeginInvoke(nbr_of_copy_exits_ , new AsyncCallback(CopyExited) , proc);
    copybutton.Enabled = false  // you don't want the button to be clicked again.
}

private void RunCopyScript(Int32 CopyScriptIdx)
{
    try
    {
        proc = ObtainProcess(client_dest_dir_ + copy_scripts_[CopyScriptIdx]);
        proc.EnableRaisingEvents = true;
        //proc.Exited += new EventHandler(CopyExited);
        proc.Start();
        progressBar.Value = ProgressInPercent(copy_scripts_.Count() , CopyScriptIdx);
    }
    catch (Exception ex)
    {
        UpdateControl(this.toolStripStatusLabel1, "Error involving " + copy_scripts_[CopyScriptIdx] + ": " + 
            ex.Message);
        copybutton.BackColor = Color.Red;
    }
    //return;
}

void CopyExited(IAsyncResult iaRes)
{
    AsyncResult result = (AsyncResult)iaRes;
    RunScript caller = (RunScript)result.AsyncDelegate;

    Process senderProcess = (Process)iaRes.AsyncState;
    caller.EndInvoke(iaRes);

    if (++this.nbr_of_copy_exits_ == this.copy_scripts_.Count())
    {
        UpdateControl(toolStripStatusLabel1 , "Copying COMPLETE.");
        copybutton.Enabled = true;   // enable the button now that we're done
    }
    else
    {
        // start the process all over again
        iaRes = caller.BeginInvoke(this.nbr_of_copy_exits_ , new AsyncCallback(CopyExited) , proc);
    }
}

private void UpdateControl(ToolStripStatusLabel tssl , String text)
{
    Invoke((MethodInvoker)delegate
    {
        tssl.Text = text;
        progressBar.Value = 0;
    });

    //tssl.Refresh();  'System.Windows.Forms.ToolStripStatusLabel' does not contain a definition for 'Refresh'...
}

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

...