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

StackOverflow https://stackoverflow.com/questions/12095

Вопрос

Наша команда создает новую систему документооборота при подборе персонала взамен старой.Мне было поручено перенести старые данные в новую схему.Я решил сделать это, создав небольшой проект 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?Это делает в значительной степени именно то, что вы делаете, но стандартизированным образом (т.е.без ваших собственных делегатов) и без необходимости создавать новый поток - оба из которых являются (возможно, небольшими, но, возможно, все еще полезными) преимуществами.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top