Geeks With Blogs
Łukasz Kuryło's blog

I'm not a desktop application developer. I wrote only one app using the WinForms, but I must tell, it was interesting experience. Now I'm writting second WinForms app and second time, I needed the possibility to updating the progress bar in an app.

So I think this is a good opportunity to put on the blog the code snippet for that to have a place where I can have some useful code for future references.

 

Ok, so let's go to the solution details. As every desktop application developer know (or should know), the WinForms controls can be accessed/property changed only from the same thread in which they were created. If we have an application and we try to change the progress bar value in some long-running algorithm and all works on the same thread, the program won't be responding to the moment that the algorithm will be over. This is not a situation we want. We want to have a responding gui for e.g. stopping the executing algorithm or simply we want to move the app window to other place on the screen. To have this possibility, the algorithm must be running in other thread and only the gui must be updating from the main thread.

In .NET Framework we have few choices to do that. We have BackgroundWorker class, Dispatcher or we can use Tasks from Task Parallel Library. In my first WinForms app I used the Tasks from TPL to do that so I will focus on this topic in this post.

In the code below is the example

       public static File[] Search(SearchCriteria criteria, INotifyProgress notify)
        {
            notifyHandler = notify;
            TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
            if (notify != null)
            {
                notify.MinValue = notify.CurrentValue = 0;
                notify.MaxValue = criteria.Locations.ToList().Count;
            }

            notify.MaxValue = 1000;
            for (int i = 1; i <= 1000; i++)
            {
                var task = Task.Factory.StartNew((variables) =>
                    {
                        //simulate some long running algorithm
                        Thread.Sleep(100);

                        return (int)variables; //return the iteration number
                    }, i);
                task.ContinueWith(x =>
                {
                    notify.CurrentValue = x.Result;
                }, scheduler);
            }

            return null;
        }

The for loop is important in this solution. As you can see, for each iteration there is creating a new Task which doing some long-running calculations. When algorithm is finished, the result is returned. Each Task has also a continuation, which is executed after the Task is finished. In this sample, in the continuation there is taken the Task result and this result is set to the progress bar Value property. As I told earlier, the controls can be changed only from the thread where they were created. This is why I used the TaskScheduler.FromCurrentSynchronizationContext() method and set is as a second parameter to the Task continuation. You probably see that, the main Task has a second parameter too. In this parameter we can provide any outer variables which we want to have access to inside the Task. The variables is an alias for our outer variables.

 

The INotifyProgress interface need one line of explanation too. This is a contract for the class which is a simple wrapper for the WinForms progress bar control. I used it, because I don't want to have reference from the business logic to the gui controls.

    public interface INotifyProgress
    {
        int MaxValue { set; get; }
        int MinValue { set; get; }
        int CurrentValue { set; get; }
    }

    public class NotifyProgressBar : INotifyProgress
    {
        private ProgressBar progressBar;

        public NotifyProgressBar(ProgressBar progressBar)
        {
            this.progressBar = progressBar;
        }

        public int MaxValue
        {
            get
            {
                return progressBar.Maximum;
            }
            set
            {
                progressBar.Maximum = value;
            }
        }

        public int MinValue
        {
            get
            {
                return progressBar.Minimum;
            }
            set
            {
                progressBar.Minimum = value;
            }
        }

        public int CurrentValue
        {
            get
            {
                return progressBar.Value;
            }
            set
            {
                progressBar.Value = value;
            }
        }
    }
Posted on Wednesday, August 17, 2011 5:42 PM useful snippets , WinForms , TPL | Back to top


Comments on this post: Updating WinForms progress bar using Tasks from Task Parallel Library

Comments are closed.
Comments have been closed on this topic.
Copyright © Łukasz Kuryło | Powered by: GeeksWithBlogs.net