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

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

Ответы [ 6 ]

2 голосов
/ 15 августа 2008

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

0 голосов
/ 15 августа 2008

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

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

0 голосов
/ 15 августа 2008

@ Джон

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

@ Will

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

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

@ Все

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

0 голосов
/ 15 августа 2008

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

0 голосов
/ 15 августа 2008

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

0 голосов
/ 15 августа 2008

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...