Потоки и события 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, кажется, обновляется очень быстро, но индикатор выполнения никогда не перемещается, пока пакет почти не завершится ??? что дает ?
Может быть, вы можете попробовать компонент BackgroundWorker. Это облегчает работу с потоками. Примеры здесь:
Вы уверены, что поток пользовательского интерфейса работает свободно в течение всего этого процесса? то есть он не сидит заблокирован на присоединении или какое-то другое ожидание? Вот как это выглядит для меня.
Предложение использования BackgroundWorker является хорошим - определенно лучше, чем попытка кувалдой выйти из проблемы с помощью загрузки вызовов «Обновить / обновить».
И BackgroundWorker будет использовать поток пула, который является более дружественным способом поведения, чем создание собственного краткосрочного потока.
Может быть, выходит за рамки, но иногда полезно сделать так, Application.DoEvents();
чтобы части графического интерфейса реагировали на ввод пользователя, например, нажав кнопку отмены в диалоговом окне строки состояния.
Вы случайно не запускаете Windows Vista? Я заметил то же самое в некоторых приложениях, связанных с работой. Почему-то кажется, что задержка, когда индикатор выполнения «оживляет».
@John
Спасибо за ссылки.
@Будет
Нет никакой выгоды от объединения потоков, так как я знаю, что это когда-либо будет порождать только один поток. Использование потока просто для того, чтобы иметь отзывчивый пользовательский интерфейс, в то время как SQL Server работает с операциями чтения и записи. Это, конечно, не недолговечный поток.
По поводу кувалд ты прав. Но, как оказалось, моя проблема была между экраном и стулом в конце концов. У меня, кажется, есть необычный пакет данных, который имеет много-много-много больше записей внешнего ключа, чем другие пакеты, и просто случайно выбран в начале процесса, означающего, что currentProgress не получает ++ 'd в течение хороших 10 секунд.
@Все
Спасибо за ваш вклад, это заставило меня задуматься, что заставило меня взглянуть в другом месте кода, что привело к моему скромному моменту ахаа, когда я еще раз доказываю, что ошибка обычно является человеческой :)
Нет никакой выгоды от объединения потоков, так как я знаю, что это когда-либо будет порождать только один поток. Использование потока просто для того, чтобы иметь отзывчивый пользовательский интерфейс, в то время как SQL Server работает с операциями чтения и записи. Это, конечно, не недолговечный поток.
Хорошо, я ценю это и рад, что вы нашли свою ошибку, но вы смотрели на BackgroundWorker? Он делает в значительной степени именно то, что вы делаете, но стандартизированным способом (т.е. без ваших собственных делегатов) и без необходимости создавать новый поток - оба из которых (возможно, небольшие, но, возможно, все же полезные) преимущества.