Потоки Windows Forms и события - ListBox обновляется быстро, но progressbar испытывает огромную задержку
-
08-06-2019 - |
Вопрос
Наша команда создает новую систему документооборота при подборе персонала взамен старой.Мне было поручено перенести старые данные в новую схему.Я решил сделать это, создав небольшой проект 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 для индикатора выполнения и текущее значение progress 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, похоже, обновляется очень быстро, но индикатор выполнения все равно никогда не перемещается, пока пакет не будет почти завершен???что это дает ?
Решение 4
@Джон
Спасибо за ссылки.
@Воля
Нет никакой выгоды от threadpooling, поскольку я знаю, что он всегда будет порождать только один поток.Использование потока предназначено исключительно для того, чтобы иметь адаптивный пользовательский интерфейс, в то время как SQL Server загружается операциями чтения и записи.Это, конечно, не недолговечная нить.
Относительно кувалд вы правы.Но, как оказалось, моя проблема все-таки была между экраном и стулом.Кажется, у меня есть необычный пакет данных, который содержит намного, намного больше записей внешнего ключа, чем другие пакеты, и просто случайно выбирается на ранней стадии процесса, что означает, что currentProgress не получает ++'d в течение добрых 10 секунд.
@Все
Спасибо за весь ваш вклад, это заставило меня задуматься, что заставило меня поискать в другом месте кода, что привело к моему ага-моменту смирения, когда я еще раз доказываю, что ошибка обычно бывает человеческой :)
Другие советы
Может быть, вы сможете попробовать компонент BackgroundWorker.Это облегчает нарезание резьбы.Примеры здесь:
Может быть, это выходит за рамки, но иногда бывает полезно сделать Application.DoEvents();
чтобы части графического интерфейса реагировали на ввод данных пользователем, например, при нажатии кнопки "Отмена" в диалоговом окне строки состояния.
Вы случайно не используете Windows Vista?Я заметил точно такую же вещь в некоторых приложениях, связанных с работой.Каким-то образом, кажется, возникает задержка, когда индикатор выполнения "анимируется".
Вы уверены, что поток пользовательского интерфейса работает свободно во время всего этого процесса?т. е.это не заблокировано при присоединении или каком-то другом ожидании?Вот на что это похоже для меня.
Предложение использовать BackgroundWorker является хорошим - определенно лучше, чем пытаться найти выход из проблемы с помощью множества вызовов обновления.
И BackgroundWorker будет использовать поток пула, что является более удобным способом поведения, чем создание вашего собственного недолговечного потока.
Нет никакой выгоды от threadpooling, поскольку Я знаю, что он будет порождать только один поток.Использование нитки-чисто чтобы иметь отзывчивый пользовательский интерфейс во время работы SQL Сервер перегружен операциями чтения и записи.Это, конечно, не короткий жил резьбы.
Хорошо, я ценю это и рад, что вы нашли свою ошибку, но вы смотрели BackgroundWorker?Это делает в значительной степени именно то, что вы делаете, но стандартизированным образом (т.е.без ваших собственных делегатов) и без необходимости создавать новый поток - оба из которых являются (возможно, небольшими, но, возможно, все еще полезными) преимуществами.