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

сценарий

Допустим, у вас есть приложение C # WinForms, которое выполняет некоторую обработку данных. У вас есть метод, который извлекает данные из базы данных, которая вызывается потоком пользовательского интерфейса. Затем выполняется фоновый поток для выполнения этой задачи. Вы хотите, чтобы пользовательский интерфейс продолжал делать свое дело, а не был заблокирован и не отвечал.

ВОПРОС

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

Ответы на вопрос(10)

можно использовать класс BackgroundWorker.

Кроме того, вы можете сделать что-то похожее на следующее:

void buttonGo_Clicked( object sender, EventArgs e )
{
    MyAsyncClass class = new MyAsyncClass();
    class.LongOperationFinished += (LongOperationFinishedEventHandler)finished;
    class.BeginLongOperation();
}

void finished( object sender, EventArgs e )
{
    if( this.InvokeRequired ) {
        this.BeginInvoke( (LongOperationFinishedEventHandler)finished, sender, e );
        return;
    }
    // You can safely modify the gui here.
}

рфейса, используя Dispatcher.CurrentDispatcher (очевидно, в методе, вызываемом потоком GUI). Используя этот объект, вы можете использовать методы BeginInvoke или Invoke в вашем рабочем потоке, чтобы выполнить метод в потоке GUI, уведомив его о том, что вы завершили работу. Лично я считаю, что этот метод немного более гибок, чем использование фонового рабочего объекта, и может создавать немного более читаемый код.

BackgroundWorker выполнять обработку времени в его обработчике событий DoWork. Затем обработайте событие RunWorkerComplete - оно сработает после завершения метода DoWork. Пока все это происходит, ваш поток пользовательского интерфейса будет радостно работать.

 Adam Lear06 нояб. 2009 г., 02:27
Я буду печатать быстрее в следующий раз. :)
 Anderson Imes06 нояб. 2009 г., 00:20
С интервалом в 20 секунд :)

BackgroundWorker нить. Имеет свойRunWorkerCompleted событие, которое делает именно то, что вам нужно.

Я очень рекомендую BackgroundWorker на самом деле. Он обладает функциональностью, которой придерживаются большинство разработчиков при создании потоков. Oни'Их также легче отменить, и они даже имеют возможность сообщать о прогрессе.

Решение Вопроса

Если вы нене использоватьфоновый работник поток (по любой причине), то вы должны запустить событие из вашего потока, которое обрабатывается потоком пользовательского интерфейса. Например, у меня есть этот код, который сканирует мои mp3-файлы и события и события для каждого найденного альбома, а затем другое событие, когда он закончился (или остановился):

    public void Build()
    {
        FindAlbums(Root);

        // Final update
        if (Library_Finished != null)
        {
            Library_Finished(this, null);
        }
    }

    private void FindAlbums(string root)
    {
        // Find all the albums
        string[] folders = Directory.GetDirectories(root);
        foreach (string folder in folders)
        {
            string[] files = Directory.GetFiles(folder, "*.mp3");
            if (files.Length > 0)
            {
                // Add to library - use first file as being representative of the whole album
                var info = new AlbumInfo(files[0]);
                if (Library_AlbumAdded != null)
                {
                    Library_AlbumAdded(this, new AlbumInfoEventArgs(info));
                }
            }

            FindAlbums(folder);
        }
    }

Затем в потоке пользовательского интерфейса (это код WinForms):

    private void Library_AlbumAdded(object sender, AlbumInfoEventArgs e)
    {
        if (dataGridView.InvokeRequired)
        {
            dataGridView.Invoke((MethodInvoker)delegate { AddToGrid(e.AlbumInfo); });
        }
        else
        {
            AddToGrid(e.AlbumInfo);
        }
    }

    private void Library_Finished(object sender, EventArgs e)
    {
        if (dataGridView.InvokeRequired)
        {
            dataGridView.Invoke((MethodInvoker)delegate { FinalUpdate(); });
        }
        else
        {
            FinalUpdate();
        }
    }

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

.InvokeRequired), чтобы перенаправить обратный вызов в поток пользовательского интерфейса. Ты нетак много уведомляет поток пользовательского интерфейса - он продолжает идти и неt ожидать какого-либо завершения, но вы можете взаимодействовать с элементом управления (например, обновить свойство текста метки) из другого потока, используя метод Invoke.

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

ля его события RunWorkerCompleted.

Это простой способ работы с несколькими потоками в C #. Это называется BackgroundWorker. Вам стоит это увидеть:BackgroundWorker Tutorial

вы можете вносить изменения в любые объекты пользовательского интерфейса, используя метод Invoke в вашей форме (или любой из элементов управления в форме). Вы также можете найти полезным свойство InvokeRequired

но самый простой способ - использовать BackgroundWorker.

По сути, у него есть два делегата, DoWork и WorkCompleted. DoWork выполняется в отдельном потоке, а обратный вызов WorkCompleted происходит в потоке пользовательского интерфейса.

Вот'Более подробная информация:http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Ваш ответ на вопрос