Developing Responsive User Interfaces (UI) using Multithreading in C#

by Jagadish Pulakhandam on 11/10/2011 12:50:52 PM
Rated 0 from 0 votes
Brief: This article demonstrates on working with Multithreading in Windows Forms to resolve application being frozen from responding to user or the problematic "Not Responding" issue
Posted to: Microsoft Windows Forms - Advanced
Add to DiggAdd to del.icio.usAdd to FURLAdd to RedditAdd to YahooAdd to BlinklistAdd to GoogleAdd to ma.gnoliaAdd to ShadowsAdd to Technorati

This article demonstrates the following:
  • A long running job (a simple loop which repeats 10000 times) updating Windows Forms user interface (UI)
  • Windows Forms application (UI) frozen due to long running job (leading to "Not Responding" issue)
  • Resolving the issue by implementing Multithreading to execute the process.  Process gets executed as part of worker thread (and not UI thread).
  • Updating Windows Forms controls from another thread (worker thread)
  • delegates using classic .NET style and using advanced lambda style
Screenshot:



Source Code:

001.using System;
002.using System.Collections.Generic;
003.using System.ComponentModel;
004.using System.Data;
005.using System.Drawing;
006.using System.Linq;
007.using System.Text;
008.using System.Windows.Forms;
009. 
010.using System.Threading;
011. 
012.namespace ThreadingDemo
013.{
014.    public partial class Form1 : Form
015.    {
016.        public Form1()
017.        {
018.            InitializeComponent();
019.        }
020. 
021.        private void btnDoProcess_Click(object sender, EventArgs e)
022.        {
023.            //Every application starts with a thread (called main/UI thread)
024. 
025.            //the loop runs on main thread (also called as UI thread in Win Forms)
026.            for (int i = 0; i < 10000; i++)
027.            {
028.                //does the job, but freezes application till the loop completes (UI thread is too busy with loop)
029.                lblMsg.Text = i.ToString();
030.                txtMsg.Text = i.ToString();
031.            }
032.            //you will only see 10000 at the end (you will not see numbers being updated from 0 to 10000)
033.        }
034. 
035.        private void btnDoProcessWithoutFreeze_Click(object sender, EventArgs e)
036.        {
037.            //execute the process on another thread called worker thread (and leave UI thread idle to respond to user events)
038.            Thread t = new Thread(new ThreadStart(DoProcess));
039.            t.Start();//this would start our process on worker thread (UI thread will be idle)
040. 
041.            //the execution continues to this line even though the process (in worker thread) is still in its progress
042.        }
043. 
044.        public void DoProcess()
045.        {
046.            //this method is executed on a worker thread (separated from UI thread)
047.            //controls on the UI thread cannot be modified from worker thread.
048.            //have to use delegates to update the controls
049.            for (int i = 0; i < 100000; i++)
050.            {
051.                //for classic .NET (see region down)
052.                //-----------------------------------
053.                //UpdateLabel(i);
054.                //UpdateTextBox(i);
055. 
056. 
057. 
058.                //advanced way using Lambda expressions and anonymous delegates
059.                Invoke(new MethodInvoker(() => lblMsg.Text = i.ToString()));
060.                Invoke(new MethodInvoker(() => txtMsg.Text = i.ToString()));
061.            }
062. 
063. 
064.        }
065. 
066. 
067.        #region for classic .NET
068. 
069.        delegate void UpdateLabelDelegate(int i);
070.        public void UpdateLabel(int i)
071.        {
072.            if (lblMsg.InvokeRequired)
073.            {
074.                UpdateLabelDelegate d = new UpdateLabelDelegate(UpdateLabel);
075.                this.Invoke(d, new object[] { i });
076.            }
077.            else
078.            {
079.                lblMsg.Text = i.ToString();
080.            }
081.        }
082. 
083. 
084.        delegate void UpdateTextBoxDelegate(int i);
085.        public void UpdateTextBox(int i)
086.        {
087.            if (txtMsg.InvokeRequired)
088.            {
089.                UpdateTextBoxDelegate d = new UpdateTextBoxDelegate(UpdateTextBox);
090.                this.Invoke(d, new object[] { i });
091.            }
092.            else
093.            {
094.                txtMsg.Text = i.ToString();
095.            }
096.        }
097. 
098.        #endregion
099.    }
100.}


Join the .NET Code Central Community and join the discussion!
Signing-up is FREE and quick. Do it now, we want to hear your opinion
0

Rated 0 from 0 votes ( login  to rate)
DotnetKicks DotnetKicksDe DotNetShoutout

Attachments / Source Code
You need to Login or Join for FREE to download the following