UI Updates – Part 1

Updating the UI is a problem and it is tricky. There are very few simple rules to follow. Let’s see Here we’ll see  some smart ways to perform UI updates on Console applications, Windows Forms, WPF, ASP.NET, Silverlight, Windows Phone and Windows Store apps.

Console Applications

Do they have UI ? No. But we’ll check how different threads perform updates on Console applications. Look at the following code. It has a main thread and another thread (worker thread) perform some time consuming task and updates the UI. Main thread shows a rotating bar till the worker thread completes.

   1: class Program

   2:     {

   3:         static void Main(string[] args)

   4:         {

   5:             Console.WriteLine("Application Start");

   6:             Thread worker = new Thread(PerformTask);

   7:  

   8:             worker.Start();

   9:  

  10:             ShowConsoleWaitAnimation(worker);

  11:  

  12:             Console.WriteLine("Application End");

  13:             Console.ReadKey();

  14:  

  15:         }

  16:  

  17:  

  18:         private static void PerformTask()

  19:         {

  20:             // job time 4 - 10 seconds

  21:             int time = new Random().Next(4,11);

  22:             Thread.Sleep(1000 * time);

  23:             Console.WriteLine("Hello from worker - ran for {0} seconds",time);

  24:         }

  25:  

  26:  

  27:         private static void ShowConsoleWaitAnimation(Thread thread)

  28:         {

  29:             while (thread.IsAlive)

  30:             {

  31:                 Console.Write("Processing - /\r");

  32:                 Thread.Sleep(100);

  33:                 Console.Write("Processing - -\r");

  34:                 Thread.Sleep(100);

  35:                 Console.Write("Processing - \\\r");

  36:                 Thread.Sleep(100);

  37:                 Console.Write("Processing - |\r");

  38:                 Thread.Sleep(100);

  39:             }

  40:         }

  41:     }

 

Windows Forms

Look at the below code. In a simple Windows Forms application, for a button click event, a time consuming task runs in a separate thread and tries to update a Label control.

   1: private void BtnStartWork_Click(object sender, EventArgs e)

   2: {

   3:     Thread worker = new Thread(PerformTask);

   4:     worker.Start();

   5: }

   6:  

   7: private void PerformTask()

   8: {

   9:     // job time 4 - 10 seconds

  10:     int time = new Random().Next(4, 11);

  11:     Thread.Sleep(1000 * time);

  12:     LblStatus.Text = String.Format("Work completed - ran for {0} seconds", time);

  13: } 

 

When you run the above code, you will get this famous Exception. Because the Label control is created in UI thread and our worker thread tries to reach it. Cross thread referencing cannot happen as this is a violation of operating system thread handling policies. ( Do not mistake the cross thread communication and cross thread referencing, cross thread communication can happen among threads)

image

There are plenty of solutions for this problem, but the ready made one is to use BackgroundWorker class. The below code shows how you can use BackgroundWorker class and perform UI updates and also shows a progress bar on the UI. Events are coded inline to reduce the number of methods for this small demo.

   1: public partial class Form1 : Form

   2: {       

   3:        private BackgroundWorker _bgWorker = new BackgroundWorker();

   4:        private string _result = String.Empty;

   5:  

   6:        public Form1()

   7:        {

   8:            InitializeComponent();

   9:        }

  10:  

  11:        private void BtnStartWork_Click(object sender, EventArgs e)

  12:        {

  13:            _bgWorker.WorkerReportsProgress = true;

  14:  

  15:            _bgWorker.DoWork += (s, ev) =>

  16:                {

  17:                    _result = PerformTask();

  18:                };

  19:            

  20:            _bgWorker.ProgressChanged += (s, ev) =>

  21:                {

  22:                    workerProgressBar.Value = ev.ProgressPercentage * 100;

  23:                };

  24:  

  25:            _bgWorker.RunWorkerCompleted += (s, ev) =>

  26:                {

  27:                    LblStatus.Text = _result;

  28:                };

  29:  

  30:            _bgWorker.RunWorkerAsync();

  31:        }

  32:  

  33:  

  34:        private string PerformTask()

  35:        {

  36:            // job time 4 - 10 seconds

  37:            int time = new Random().Next(4, 11);

  38:            int fullTime = time;

  39:  

  40:            while (time >= 0)

  41:            {

  42:                Thread.Sleep(1000);

  43:                _bgWorker.ReportProgress(1 - (time / fullTime));

  44:                time--;

  45:            }

  46:  

  47:            return String.Format("Work completed - ran for {0} seconds", fullTime);

  48:         }

  49:           

  50: } 

 

WPF

In WPF we can use the BackgroundWorker, but also there’s a well refined solution in the WPF is to use the Dispatcher object. WPF model has Dispatcher object common across all the controls. So we can use this to update the UI.

Little modification in the PerformTask() and make it return the result.

   1: private string PerformTask()

   2: {

   3:     // job time 4 - 10 seconds

   4:     int time = new Random().Next(4, 11);

   5:     int fullTime = time;

   6:  

   7:     Thread.Sleep(time);      

   8:  

   9:     return String.Format("Work completed - ran for {0} seconds", fullTime);

  10: } 

Button click event.

   1: private void BtnWork_Click(object sender, RoutedEventArgs e)

   2: {

   3:     Thread thread = new Thread(() =>

   4:         {

   5:             string result = PerformTask();

   6:             Dispatcher.Invoke(() =>

   7:                 {

   8:                     TxtStatus.Text = result;

   9:                 });

  10:         });

  11:     thread.Start();

  12: }

Part 2 – will discuss about UI updates in ASP.NET and Silverlight.

Silverlight Dispatcher

Threading in Silverlight is simple and have very few classes and limited functionality.

In Silverlight we rarely go for the threading since the platform itself is asynchronous. Click to read how to do asynchronous programming in C# 5.0

In Silverlight the  main thread is incorporated with the Dispatcher, and we can use the BeginInvoke method of the Dispatcher class to update the UI from a different thread. According to the MSDN documentation Dispatcher in Silverlight is intended for the UI updates.

I’m using a dummy method which returns a string reversed of its input. And let’s assume it takes 4 seconds to complete the task.

So we need a thread to do the work, without blocking the UI. Once the task completed we have to display the string in the UI.

Here’s my simple and the dirty UI, a TextBox, a Button and a TextBlock to show the output.

image

Here’s the code goes under the Button click event , you can do the work in a thread and return the updates to the UI safely using Dispatcher.

{
string name = textBox1.Text;
Thread thread =new Thread(() =>
{  _reversedString = ReverseString(name);
   this.Dispatcher.BeginInvoke(() =>
     {
              textBlock1.Text = _reversedString;
     });
});
thread.Name =Reverse String Thread;
thread.Start();
}

When hitting the debug and break point we can ensure that our thread is really started and running.

1

Code for the ReverseString method

private string ReverseString(string input)
{
     char[] array = input.ToCharArray();
    Array.Reverse(array);
    Thread.Sleep(4000);
    return new String(array);
}

Let’s discuss how Dispatcher can communicate across threads.

You can clearly notice that, I got the Dispatcher object using this.Dispatcher. This gives the Dispatcher of the Page (MainPage).

Dispatcher is a member of the DependencyObject class. So all the elements mainly UI controls have the Dispatcher property.

Silverlight is a Single Threaded Apartment (STA) Model. And as mentioned earlier it is incorporated with the main thread of the Silverlight. It is the thread responsible of the creation of the UI elements.

Trying to create UI elements from custom threads will throw thread exceptions as they try get the one and only Dispatcher from a different thread.

Here I compare the difference Dispatcher obrtained. First I got the Dispatcher of the RootVisual. Second the TextBlock control. Third I get the Dispatcher reference of the Deplyoment.

System.Windows.Threading.Dispatcher appDisptcher = Application.Current.RootVisual.Dispatcher;
System.Windows.Threading.Dispatcher textBlockDispatcher = textBlock1.Dispatcher;
System.Windows.Threading.Dispatcher deploymentDispatcher = System.Windows.Deployment.Current.Dispatcher;
if (appDisptcher.Equals(textBlockDispatcher))
{
    MessageBox.Show(Root Visual Dispatcher is same as TextBlock Dispatcher);
    
    if (appDisptcher.Equals(deploymentDispatcher))
    {
          MessageBox.Show(All three are same indeed);
    }
}

You can see that all Dispatchers equal. So Dispatcher works from one golden rule that is Silverlight is Single Threaded Apartment (STA) model where with that main thread Dispatcher is incorporated.

Dinning Philosopher – C#

 

This post demonstrates another threading problem. There are many solutions for dinning philosopher problem. The famous one is to introduce a waiter for the table. Where the waiter acts as the monitor and the philosophers have to ask the waiter to take a fork. Another solution is that let the philosophers talk with themselves.

But this solution has a another simple mechanism, which avoids the dead lock by it’s own by randomizing the time a philosopher can hold a single fork. Having both the forks is not randomized, since having the both forks is a ready state for eating. So even the dead lock is about to occur it never lasts. And another threshold value is used as starvation count, which represents the maximum number of continuous thinking a philosopher can bare without considered being starved.

When running this algorithm you can notice that the philosophers may get starved (mainly if the starvation count is low) but it is almost impossible for a philosopher to starve forever.

Pure object orientation and C# techniques are used in developing this code. It is true that this code is not the best one when it comes to efficiency. This code can be improved in other ways. But still it provides a self time slicing feature for the dinning philosophers problem.

using System;
using System.Threading;

namespace DinningPhilosophers
{
    class Program
    {   
        static void Main(string[] args)
        { 
            Philosopher aristotle = new Philosopher(Table.Plastic,Table.Platinum,"Aristotle",4); 
            Philosopher palto = new Philosopher(Table.Platinum, Table.Gold,"Plato",5);
            Philosopher john = new Philosopher(Table.Gold, Table.Silver,"John Dewey",6);
            Philosopher augustine = new Philosopher(Table.Silver, Table.Wood, "Augustine",4);
            Philosopher thomas = new Philosopher(Table.Wood, Table.Plastic,"Thomas Aquinas",7);

            new Thread(aristotle.Think).Start();
            new Thread(palto.Think).Start();
            new Thread(john.Think).Start();
            new Thread(augustine.Think).Start();
            new Thread(thomas.Think).Start();

            Console.ReadKey();
        }

    }



    enum PhilosopherState { Eating, Thinking }


    class Philosopher
    {
        public string Name { get; set; }

        public PhilosopherState State { get; set; }

        // determines number of continuose thinkings, without being considered starving
        readonly int StarvationThreshold;

        // defines the right and the left side fork of a philosopher
        public readonly Fork RightFork;
        public readonly Fork LeftFork;

        Random rand = new Random();

        int contThinkCount = 0;

        public Philosopher(Fork rightFork, Fork leftFork, string name, int starvThreshold)
        {
            RightFork = rightFork;
            LeftFork = leftFork;
            Name = name;
            State = PhilosopherState.Thinking;
            StarvationThreshold = starvThreshold;
        }

        public void Eat()
        {
            // take the fork in the right hand
            if (TakeForkInRightHand())
            {
                // if got the fork in the right hand immediatley try to take the fork in the left hand
                if (TakeForkInLeftHand())
                {
                    // if got both forks then eat
                    this.State = PhilosopherState.Eating;
                    Console.WriteLine("(:::) {0} is eating..with {1} and {2}", Name, RightFork.ForkID, LeftFork.ForkID);
                    Thread.Sleep(rand.Next(5000, 10000));

                    contThinkCount = 0;

                    // place the forks back
                    RightFork.Put();
                    LeftFork.Put();
                }
                // got the right fork but not the left one
                else
                {
                    // wait for a small random period and try agian to get left fork
                    Thread.Sleep(rand.Next(100, 400));
                    if (TakeForkInLeftHand())
                    {
                        // if got the left fork then eat
                        this.State = PhilosopherState.Eating;
                        Console.WriteLine("(:::) {0} is eating..with {1} and {2}", Name, RightFork.ForkID, LeftFork.ForkID);
                        Thread.Sleep(rand.Next(5000, 10000));

                        contThinkCount = 0;

                        RightFork.Put();
                        LeftFork.Put();
                    }
                    // if couldn't get the fork even after the wait, out the right fork on the table
                    else
                    {
                        RightFork.Put();
                    }
                }
            }
            // if couldn't get fork on the right hand
            else
            {
                // get a fork the left hand
                if (TakeForkInLeftHand())
                {
                    // wait for a small random time period and then try acquire the right one
                    Thread.Sleep(rand.Next(100, 400));
                    if (TakeForkInRightHand())
                    {
                        // if got the right one then eat
                        this.State = PhilosopherState.Eating;
                        Console.WriteLine("(:::) {0} is eating..with {1} and {2}", Name, RightFork.ForkID, LeftFork.ForkID);
                        Thread.Sleep(rand.Next(5000, 10000));

                        contThinkCount = 0;

                        RightFork.Put();
                        LeftFork.Put();
                    }
                    else
                    {
                        // else put the left fork back on the table
                        LeftFork.Put();
                    }
                }
            }

            Think();
        }

        public void Think()
        {
            this.State = PhilosopherState.Thinking;
            Console.WriteLine("^^*^^ {0} is thinking...on {1}", Name, Thread.CurrentThread.Priority.ToString());
            Thread.Sleep(rand.Next(2500,20000));
            contThinkCount++;

            if (contThinkCount > StarvationThreshold)
            {
                Console.WriteLine(":ooooooooooooooooooooooooooooooooooooooooooooooo: {0} is starving", Name);
            }

            Eat();
        }

        private bool TakeForkInLeftHand()
        {
            return LeftFork.Take(Name);
        }

        private bool TakeForkInRightHand()
        {
            return RightFork.Take(Name);
        }

    }




    enum ForkState { Taken, OnTheTable }
    

    class Fork
    {
        public string ForkID { get; set; }
        public ForkState State { get; set; }
        public string TakenBy { get; set; }

        public bool Take(string takenBy)
        {
            lock (this)
            {
                if (this.State == ForkState.OnTheTable)
                {
                    State = ForkState.Taken;
                    TakenBy = takenBy;
                    Console.WriteLine("||| {0} is taken by {1}", ForkID, TakenBy);
                    return true;
                }

                else
                {
                    State = ForkState.Taken;
                    return false;
                }
            }
        }

        public void Put()
        {
            State = ForkState.OnTheTable;
            Console.WriteLine("||| {0} is place on the table by {1}", ForkID, TakenBy);
            TakenBy = String.Empty;   
        }
    }



    class Table
    {
        internal static Fork Platinum = new Fork () { ForkID = "Platinum Fork", State = ForkState.OnTheTable};
        internal static Fork Gold = new Fork() { ForkID = "Gold Fork", State = ForkState.OnTheTable };
        internal static Fork Silver = new Fork() { ForkID = "Silver Fork", State = ForkState.OnTheTable };
        internal static Fork Wood = new Fork() { ForkID = "Wood Fork", State = ForkState.OnTheTable };
        internal static Fork Plastic = new Fork() { ForkID = "Plastic Fork", State = ForkState.OnTheTable };
    }
}

Simple Client–Server in C#

 

This is a very simplest client server model which is only to demonstrate the client server working model. And a simple program to learn threads in C#.

Client connects to the server and then server delivers a unique number to each client by simply incrementing a static variable. The increment is locked for thread safety.

Code for the server.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Threading;

namespace ConsoleServer
{
    class Program
    {
        static TcpListener server;
        static int count = 0;
        static readonly object o = new object();

        static void Main(string[] args)
        {
            IPHostEntry host = Dns.GetHostEntry("localhost");
            IPAddress ip = new IPAddress(host.AddressList.First().GetAddressBytes());

            server = new TcpListener(ip, 2000);
            server.Start();

            bool exit = false;

            Console.WriteLine("Server started on port 2000");

            while (!exit)
            {
                // here pending requests are in a queue.
                if (server.Pending())
                {
                    new Thread(Program.ServerService).Start();
                }
            }

            Console.ReadKey();
            server.Stop();

        }

        public static void ServerService()
        {
            Socket socket = server.AcceptSocket();

            Console.WriteLine("Connected " + socket.RemoteEndPoint);

            Stream stream = new NetworkStream(socket);
            StreamWriter writer = new StreamWriter(stream);
            StreamReader reader = new StreamReader(stream);

            writer.AutoFlush = true;
        
            writer.Write("Initial Number {0}",GetNumber());

            bool client = false;

            new Thread(() =>
            {
                while (!client)
                {
                    string s = "";
                    s = reader.ReadLine();

                    if (s == "req")
                    {
                        writer.Write(GetNumber());
                        writer.Flush();
                    }
                }
            }).Start();
        }

        private static int GetNumber()
        {
            // here sleep time gets activated after one client leaves the lock block.
            // so if a first client gets short long sleep time and second one gets short, still the second one has to wait till the first one finishes.

            Random r = new Random();
            int time = r.Next(200, 2000);
            Console.WriteLine("Sleeping time : {0}", time);

            lock(o)
            {
                Thread.Sleep(time);
                return ++count;
            }
        }
    }
}


Code for the client

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace ConsoleClient
{
    class Program
    {
        static void Main(string[] args)
        {
            TcpClient client = new TcpClient("localhost", 2000);

            Stream stream = client.GetStream();
            StreamReader reader = new StreamReader(stream);

            Console.WriteLine(reader.ReadLine());

            stream.Flush();
            
            new Thread(() =>
             {
                 Console.WriteLine("New Request {0} ", reader.ReadLine());

                 Console.WriteLine("Waiting for exit");
                 Console.ReadKey();
             }).Start();

 

            while (true)
            {
                string req = Console.ReadLine();

                if (req == "new")
                {
                    StreamWriter writer = new StreamWriter(stream);
                    writer.Write(req);
                    writer.Flush();
                }
            }
            client.Close();

        }
    }
}