Windows Forms Threading and Events - ListBox updat

2019-05-07 02:40发布

Our team is creating a new recruitment workflow system to replace an old one. I have been tasked with migrating the old data into the new schema. I have decided to do this by creating a small Windows Forms project as the schema are radically different and straight TSQL scripts are not an adequate solution.

The main sealed class 'ImportController' that does the work declares the following delegate event:

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

The main window starts a static method in that class using a new thread:

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

the ImportProgressEvent args carries a string message, a max int value for the progress bar and an current progress int value. The Windows form subcribes to the event:

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

And responds to the event in this manner using it's own delegate:

    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);
            }

Finally the progress bar and listbox are updated:

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;
            }
        }

The thing is the ListBox seems to update very quickly, but the progress bar never moves until the batch is almost complete anyway ??? what gives ?

6条回答
ら.Afraid
2楼-- · 2019-05-07 02:50

There's no gain from threadpooling as I know it will only ever spawn one thread. The use of a thread is purely to have a responsive UI while SQL Server is being pounded with reads and writes. It's certainly not a short lived thread.

OK, I appreciate that, and glad you found your bug, but have you looked at BackgroundWorker? It does pretty much exactly what you're doing, but in a standardised fashion (i.e. without your own delegates) and without the need to create a new thread - both of which are (perhaps small, but maybe still useful) advantages.

查看更多
等我变得足够好
3楼-- · 2019-05-07 03:02

Do you by any chance run Windows Vista? I've noticed the exactly same thing in some work related applications. Somehow, there seem to be a delay when the progress bar "animates".

查看更多
够拽才男人
4楼-- · 2019-05-07 03:03

Are you sure that the UI thread is running freely during all this process? i.e. it's not sitting blocked-up on a Join or some other wait? That's what it looks like to me.

The suggestion of using BackgroundWorker is a good one - definitely superior to trying to sledge-hammer your way out of the problem with a load of Refresh/Update calls.

And BackgroundWorker will use a pool thread, which is a friendlier way to behave than creating your own short-lived thread.

查看更多
疯言疯语
5楼-- · 2019-05-07 03:04

Maybe you can try the BackgroundWorker component. It makes threading easier. Examples here:

查看更多
做自己的国王
6楼-- · 2019-05-07 03:08

Maybe outside of the scope but, to sometimes its useful to do an Application.DoEvents(); to make the gui parts react to user input, such as pressing the cancel-button on a status bar dialog.

查看更多
放荡不羁爱自由
7楼-- · 2019-05-07 03:08

@John

Thanks for the links.

@Will

There's no gain from threadpooling as I know it will only ever spawn one thread. The use of a thread is purely to have a responsive UI while SQL Server is being pounded with reads and writes. It's certainly not a short lived thread.

Regarding sledge-hammers you're right. But, as it turns out my problem was between screen and chair after all. I seem to have an unusal batch of data that has many many many more foreign key records than the other batches and just happens to get selected early in the process meaning the currentProgress doesn't get ++'d for a good 10 seconds.

@All

Thanks for all your input, it got me thinking, which got me looking elsewhere in the code, which led to my ahaa moment of humility where I prove yet again the error is usually human :)

查看更多
登录 后发表回答