Потоки и события Windows Forms - ListBox быстро обновляется, но прогрессбар испытывает огромную задержку

Наша команда создает новую систему документооборота для замены старой. Мне было поручено перенести старые данные в новую схему. Я решил сделать это, создав небольшой проект Windows Forms, поскольку схемы радикально отличаются, а прямые сценарии TSQL не являются адекватным решением.

Основной запечатанный класс ImportController, который выполняет эту работу, объявляет следующее событие делегата:

public delegate void ImportProgressEventHandler(object sender, ImportProgressEventArgs e);
public static event ImportProgressEventHandler importProgressEvent;

Главное окно запускает статический метод в этом классе, используя новый поток:

Thread dataProcessingThread = new Thread(new ParameterizedThreadStart(ImportController.ImportData));
dataProcessingThread.Name = "Data Importer: Data Processing Thread";
dataProcessingThread.Start(settings);

Аргументы ImportProgressEvent содержат строковое сообщение, максимальное значение int для индикатора выполнения и текущее значение int прогресса. Форма Windows подписывается на событие:

ImportController.importProgressEvent += new ImportController.ImportProgressEventHandler(ImportController_importProgressEvent);

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

    private delegate void TaskCompletedUIDelegate(string completedTask, int currentProgress, int progressMax);

private void ImportController_importProgressEvent(object sender, ImportProgressEventArgs e)
            {
                this.Invoke(new TaskCompletedUIDelegate(this.DisplayCompletedTask), e.CompletedTask, e.CurrentProgress, e.ProgressMax);
            }

Наконец, индикатор выполнения и список обновляются:

private void DisplayCompletedTask(string completedTask, int currentProgress, int progressMax)
        {
            string[] items = completedTask.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);

            foreach (string item in items)
            {
                this.lstTasks.Items.Add(item);
            }

            if (currentProgress >= 0 && progressMax > 0 && currentProgress <= progressMax)
            {
                this.ImportProgressBar.Maximum = progressMax;
                this.ImportProgressBar.Value = currentProgress;
            }
        }

Дело в том, что ListBox, кажется, обновляется очень быстро, но индикатор выполнения никогда не перемещается, пока пакет почти не завершится ??? что дает ?

15.08.2008 09:19:04
6 ОТВЕТОВ

Может быть, вы можете попробовать компонент BackgroundWorker. Это облегчает работу с потоками. Примеры здесь:

2
15.08.2008 09:38:36

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

Предложение использования BackgroundWorker является хорошим - определенно лучше, чем попытка кувалдой выйти из проблемы с помощью загрузки вызовов «Обновить / обновить».

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

-1
15.08.2008 09:50:34

Может быть, выходит за рамки, но иногда полезно сделать так, Application.DoEvents();чтобы части графического интерфейса реагировали на ввод пользователя, например, нажав кнопку отмены в диалоговом окне строки состояния.

0
15.08.2008 09:58:15

Вы случайно не запускаете Windows Vista? Я заметил то же самое в некоторых приложениях, связанных с работой. Почему-то кажется, что задержка, когда индикатор выполнения «оживляет».

0
15.08.2008 10:01:57
РЕШЕНИЕ

@John

Спасибо за ссылки.

@Будет

Нет никакой выгоды от объединения потоков, так как я знаю, что это когда-либо будет порождать только один поток. Использование потока просто для того, чтобы иметь отзывчивый пользовательский интерфейс, в то время как SQL Server работает с операциями чтения и записи. Это, конечно, не недолговечный поток.

По поводу кувалд ты прав. Но, как оказалось, моя проблема была между экраном и стулом в конце концов. У меня, кажется, есть необычный пакет данных, который имеет много-много-много больше записей внешнего ключа, чем другие пакеты, и просто случайно выбран в начале процесса, означающего, что currentProgress не получает ++ 'd в течение хороших 10 секунд.

@Все

Спасибо за ваш вклад, это заставило меня задуматься, что заставило меня взглянуть в другом месте кода, что привело к моему скромному моменту ахаа, когда я еще раз доказываю, что ошибка обычно является человеческой :)

0
15.08.2008 10:07:06

Нет никакой выгоды от объединения потоков, так как я знаю, что это когда-либо будет порождать только один поток. Использование потока просто для того, чтобы иметь отзывчивый пользовательский интерфейс, в то время как SQL Server работает с операциями чтения и записи. Это, конечно, не недолговечный поток.

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

-1
15.08.2008 10:20:01