Обновление пользовательского интерфейса Winforms из фонового потока - PullRequest
4 голосов
/ 11 июня 2009

Возможно, это глупый вопрос, но я не смог найти ответ на stackoverflow.

У меня есть событие нажатия кнопки в приложении Winform, которое запускает поток для вычисления результата для отображения в форме.

Как обновить пользовательский интерфейс форм, когда поток вычислил результат?

    private void btnRequestR2Approval_Click(object sender, EventArgs e)
    {
        if (User.IsLogged)
        {
            ValidationResults results = new ValidationResults();
            results.Show();

            Logger log = Logger.Instance();
            Logger.NewLogAddedHandler messageDelegate = new Logger.NewLogAddedHandler(results.NewLogMessage);

            if (!log.IsEventHandlerRegistered())
            {
                log.NewLogAdded += messageDelegate;
            }

            ThreadStart operation = new ThreadStart(ValidateAndSubmit);
            Thread theThread = new Thread(operation);
            theThread.Start();

        }
        else
        {
            MessageBox.Show("Please login");
        }

    }

Спасибо

Ответы [ 4 ]

13 голосов
/ 12 июня 2009

Самым простым способом выполнения фоновой задачи в WinForms является использование BackgroundWorker .

  • Перетащите его на форму.
  • Подключите события. Как минимум, используйте DoWork. Вы, вероятно, также захотите RunWorkerCompleted.
  • Напишите фоновое задание в событии DoWork.
  • Запись любых изменений пользовательского интерфейса в событии RunWorkerCompleted.
  • Вызовите backgroundWorker1.RunWorkerAsync();, чтобы запустить процесс, возможно, из какого-то обработчика кнопок.

Использование BackgroundWorker позволяет избежать всей надоедливой обработки потоков и вещей IsInvokeRequired.

Вот более подробная статья с инструкциями .

2 голосов
/ 12 июня 2009

Очень неясный вопрос, я приду:

  1. Вы используете приложение Windows Winforms, а не веб-страницу ASP.Net.
  2. Вы хотите запустить расчет фона, который может занять много времени, и не хотите, чтобы ваш пользовательский интерфейс блокировался, пока это происходит.
  3. Вы хотите, чтобы ваш пользовательский интерфейс получал какой-то результат после выполнения фонового расчета.
  4. Вы хотите, чтобы ваш фоновый расчет завершился, когда он предоставил ваш пользовательский интерфейс с результатом.

Если это так, вы должны использовать асинхронный делегат, а не поток. Например:

string SleepAndReturnParam(string param1)
{
    System.Threading.Thread.Sleep(10000);
    return param1;
}

// Declare a delegate matching our async method.
public delegate string DelegateWithParamReturningString(string param1);


private void button1_Click(object sender, EventArgs e)
{
    var myDelegate = new DelegateWithParamReturningString(SleepAndReturnParam);

    // Run delegate in thread pool.
    myDelegate.BeginInvoke("param1",
        OnCallBack, // Completion callback
        this); // value to pass to callback as AsyncState
}


private void OnCallBack(IAsyncResult ar)
{
    // first cast IAsyncResult to an AsyncResult object
    var result = ar as System.Runtime.Remoting.Messaging.AsyncResult;

    // grab the delegate
    var myDelegate = result.AsyncDelegate as DelegateWithParamReturningString;

    // Exit delegate and retrieve return value.
    string returnValue = myDelegate.EndInvoke(ar);

    // Declare an anonymous method to avoid having to define
    // a method just to update a field.
    MethodInvoker formFieldUpdater = delegate
    {
        formTextField.Text = returnValue;
    };

    // Winforms controls must be modified on the thread
    // they were created in.
    if (formTextField.InvokeRequired)
        Invoke(formFieldUpdater);
    else
        formFieldUpdater();
}
2 голосов
/ 12 июня 2009

Попробуйте использовать BeginInvoke с операцией обратного вызова ... это переместит ваш вызов в другой поток и вызовет метод по вашему выбору, когда поток завершится:

private void btnRequestR2Approval_Click(object sender, EventArgs e)
{
    if (User.IsLogged)
    {
        ValidationResults results = new ValidationResults();
        results.Show();

        Logger log = Logger.Instance();
        Logger.NewLogAddedHandler messageDelegate = new Logger.NewLogAddedHandler(results.NewLogMessage);

        if (!log.IsEventHandlerRegistered())
        {

            log.NewLogAdded += messageDelegate;
        }

        ThreadStart operation = new ThreadStart(ValidateAndSubmit);
        operation.BeginInvoke(MyCallBack, this);
    }
    else
    {
        MessageBox.Show("Please login");
    }

}

private static void MyCallBack(IAsyncResult ar) {
  ((MyForm)ar.AsyncState).Refresh();
}
0 голосов
/ 12 июня 2009

Вы можете либо 1. сделать theThread.Join(), который бы блокировал вызывающий поток. 2. Передайте первый поток второму, чтобы он мог перезвонить в главный поток, что потребует Invoke(), чтобы он мог перерисовать форму.

Мне любопытно. Вы используете Asp.Net (WebForms) или WinForms? Если вы пытаетесь сделать это в Интернете, вам понадобится совершенно другой подход.

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