C# | .NET : Smart Duration Class

C# | .NET : Smart Duration Class

[Originally posted on 11 October 13]

Sometimes you need to have start and end dates, validate whether these dates define valid duration, or determine overlapping duration/timespan in two given duration(s)? I wrote an MVVM ready, equitable, duration class which does all the above and a little more. :-). I call this class TimeDuration. Let’s go through the code of the class.

TimeDuration implements two interfaces,  IEquatable and INotifyPropertyChanged. In later parts we will see the implementation of methods for IEquatable, let’s see INotifyPropertyChanged implementation first.  It has System.ComponentModel and a PropertyChangedEventHandler type public event PropertyChanged. It has a private method onPropertyChanged with a return type void. The complete INotifyPropertyChanged implementation looks like this:

using System;
using System.ComponentModel;

namespace Demo.DateExtentions
{
    public class TimeDuration : IEquatable, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private void onPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }
}

The class encapsulate two basic information elements – start time and end time. To expose this information class has two public DateTime type properties; Start and End. To notify views when the basic information changes in VM the class calls onPropertyChanged method from inside settters of both these properties. The implementation code looks like this:

        DateTime start;
        DateTime end;
        public DateTime Start
        {
            get { return start; }
            set
            {
                if (start != value)
                {
                    start = value;
                    onPropertyChanged("Start");
                }
            }
        }
        public DateTime End
        {
            get { return end; }
            set
            {
                if (end != value)
                {
                    end = value;
                    onPropertyChanged("End");
                }
            }
        }

The class initializes DateTime structured in the constructor so that object based on this class is ready for use on initialization. Constructor looks like so:

        public TimeDuration()
        {
            start = new DateTime();
            end = new DateTime();
        }

(Fields could have been initialized at the time of defining the field and not have the constructor at all.)
Duration represents a time span, so TimeDuration class has a TimeSpan type public property named Duration. This property returns the difference of start and end times. Code is like this:

        public TimeSpan Duration { get { return end - start; } }

This part makes the class a smart duration class. TimeDuration is capable of telling intersecting duration/timespan between two given durations. Following figure illustrates intersecting durations:
DurationFigure

In the figure above AB, CD, EF, and GH represent durations. Class returns information regarding CB in the context of AB and CD, where starting part of CD overlaps with end part of AB. The method returns overlap duration if one duration completely falls inside of another duration, as in AB and EF, where EF completely lies inside AB. The third scenario is where tail part of one duration overlaps with head part of another duration as in AB and GH where overlap is occurring at AH. Following is the code to return appropriate type, TimeSpan or TimeDuration, after checking the intersection.

        public TimeSpan IntersectingSpan(TimeDuration other)
        {
            return getIntersection(other).Duration;
        }
        public TimeDuration IntersectingDuration(TimeDuration other)
        {
            return getIntersection(other);
        }
        private TimeDuration getIntersection(TimeDuration other)
        {
            if (this.Equals(other)) return this;
            DateTime iStart = this.Start < other.Start ? other.Start : this.Start;
            DateTime iEnd = this.End < other.End ? this.End : other.End;
            return iStart < iEnd ? new TimeDuration(iStart, iEnd) : new TimeDuration();
        }

IEquatable interface implementation:

        public bool Equals(TimeDuration compareWith)
        {
            return CompareWith.Start == this.Start && CompareWith.End == this.End;
        }
        public override int GetHashCode()
        {
            return _start.GetHashCode() ^ _end.GetHashCode();
        }

The entire SmartDuration class:

/*
 * Disclaimer
 * Unless otherwise noted, code snippets in this repository are licensed under a Creative Commons Attribution 4.0 International license (http://creativecommons.org/licenses/by/4.0/)
 * Please do not forget to credit if you choose to use code in any which way.  You can credit in any way you please as below:
        By Sanjay (https://sharpsnippets.wordpress.com/)
        By Sanjay (http://www.twitter.com/SanjayAtPilcrow)
 * Blog post about following code: http://wp.me/p2iWZr-4T
 * General Notes
 *      - This is working code, but not production code.
 *      - Code follows universal C# code convention but might not follow your company's internal convention.
 *      - Code is more of POC and thus does not have full exception handling and parameter checking.
 *      - If you choose to use the code in production, do re-code to make it production ready as per your org's engineering policy.
*/
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace POCs.Sanjay.SharpSnippets.Dates
{
    public class TimeDuration : IEquatable, INotifyPropertyChanged
    {
        DateTime start;
        DateTime end;
        public DateTime Start
        {
            get { return start; }
            set
            {
                if (start != value)
                {
                    start = value;
                    onPropertyChanged("Start");
                }
            }
        }
        public DateTime End
        {
            get { return end; }
            set
            {
                if (end != value)
                {
                    end = value;
                    onPropertyChanged("End");
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        public TimeDuration()
        {
            start = new DateTime();
            end = new DateTime();
        }
        public TimeDuration(DateTime start, DateTime end)
        {
            start = start;
            end = end;
        }
        public bool IsValidDuration
        {
            get { return _start <= _end; }
        }
        public TimeSpan Duration { get { return end - start; } }
        public TimeSpan IntersectingSpan(TimeDuration other)
        {
            return getIntersection(other).Duration;
        }
        public TimeDuration IntersectingDuration(TimeDuration other)
        {
            return getIntersection(other);
        }
        private TimeDuration getIntersection(TimeDuration other)
        {
            if (this.Equals(other)) return this;
            DateTime iStart = this.Start < other.Start ? other.Start : this.Start;
            DateTime iEnd = this.End < other.End ? this.End : other.End;
            return iStart < iEnd ? new TimeDuration(iStart, iEnd) : new TimeDuration();
        }

        #region Equatable
        public bool Equals(TimeDuration compareWith)
        {
            return CompareWith.Start == this.Start && CompareWith.End == this.End;
        }
        public override int GetHashCode()
        {
            return _start.GetHashCode() ^ _end.GetHashCode();
        }
        #endregion //Equatable

        #region notify property changed
        private void onPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
        #endregion

    }
}

Find code on my GitHub repository.

 

C#|.NET : Size String, Truncate Lines

Swiss Crop Circle 2009 Aerial by Kecko, on Flickr
Swiss Crop Circle 2009 Aerial, a photo by Kecko on Flickr.

I needed to truncate lines from CSV string prepared for export through mail in my app. Windows Phone mail restricts text size to 1MB. In my app’s case some CSV reports could go beyond 1MB. To make sure that the CSV report does not exceed a desired size in bytes, I created this extension method – SizeIt. SizeIt can truncate lines (and characters if required) from a given string from beginning or from end and also inserts information text line (how many lines and characters removed) in the resulting string. Following is the test form created to show what the method does to a string. In this example a 300 byte 10 line string is given as input and asked to reduce it to <200 bytes, first from beginning, and then from end.

SizeTail

SizeFront

Here is the code for the extension method:

    public static class StringBuilderExtensions
    {
        /// <summary>
        /// Sizes StringBuilder to given size
        /// </summary>
        /// <param name="sb">StringBuilder</param>
        /// <param name="bytes">Maximum Size of resultant string. Mostly the size of string will be less than max size</param>
        /// <param name="removeLinesFromBeginning">Pass true, if clipping has to happen in the beginning</param>
        public static void SizeIt(this StringBuilder sb, int bytes, bool removeLinesFromBeginning)
        {
            bool _stringReplacementHappened = false;
            bool _maxBytesAdjusted_for_lines = false;
            bool _maxBytesAdjusted_for_chars = false;
            string _insertThismessage = "";
            int _linesRemoved = 0;
            int _charsRemoved = 0;
            //try removing lines.
            while (System.Text.Encoding.Unicode.GetByteCount(sb.ToString()) > bytes)
            {
                char _alternateNewLine = '\r';
                string _workingString = sb.ToString();
                if (!_workingString.Contains(Environment.NewLine) && !_workingString.Contains(_alternateNewLine))
                {
                    break;
                }
                int _newlinelocation = sb.ToString().IndexOf(Environment.NewLine);
                int _lastNewlinelocation = sb.ToString().LastIndexOf(Environment.NewLine);
                if (_newlinelocation <= 0)
                {
                    _newlinelocation = sb.ToString().IndexOf(_alternateNewLine);
                }
                if (_lastNewlinelocation <= 0)
                {
                    _lastNewlinelocation = sb.ToString().LastIndexOf(_alternateNewLine);
                }

                if (removeLinesFromBeginning)
                {
                    sb = sb.Remove(0, _newlinelocation + 1);
                    _linesRemoved++;
                    _stringReplacementHappened = true;
                    _insertThismessage = string.Format("... {0} lines removed{1}", _linesRemoved, Environment.NewLine);
                }
                else
                {
                    int _lastReturnAt = _lastNewlinelocation;
                    int _charsInLastLine = sb.Length - _lastNewlinelocation;
                    sb = sb.Remove(_lastReturnAt, _charsInLastLine);
                    _linesRemoved++;
                    _stringReplacementHappened = true;
                    _insertThismessage = string.Format("{1}{0} lines removed...", _linesRemoved, Environment.NewLine);
                }
                if (!_maxBytesAdjusted_for_lines)
                {
                    bytes -= 50; //40 extra bytes for information text
                    _maxBytesAdjusted_for_lines = true;
                }
            }
            //if it's still more than the desired size
            if (System.Text.Encoding.Unicode.GetByteCount(sb.ToString()) > bytes)
            {
                int _currentBytes = System.Text.Encoding.Unicode.GetByteCount(sb.ToString());
                if (!_maxBytesAdjusted_for_lines)
                {
                    bytes -= 100;
                    _maxBytesAdjusted_for_lines = true;
                    _maxBytesAdjusted_for_chars = true;
                }
                else if (!_maxBytesAdjusted_for_chars)
                {
                    bytes -= 50;
                    _maxBytesAdjusted_for_chars = true;
                }
                int _removeChars = (_currentBytes - bytes) / 2;
                if (removeLinesFromBeginning)
                {
                    sb = sb.Remove(0, _removeChars);
                    _stringReplacementHappened = true;
                    _insertThismessage = string.Format("... {0} lines and {1} chars removed{2}", _linesRemoved, _removeChars, Environment.NewLine);
                }
                else
                {
                    sb = sb.Remove(sb.Length - _removeChars, _removeChars);
                    _stringReplacementHappened = true;
                    _insertThismessage = string.Format("{2}{0} lines and {1} chars removed...", _linesRemoved, _removeChars, Environment.NewLine);
                }
            }
            if (_stringReplacementHappened)
            {
                if (removeLinesFromBeginning)
                {
                    sb.Insert(0, _insertThismessage);
                }
                else
                {
                    sb.Append(_insertThismessage);
                }
            }
        }
    }

You may extend SizeIt to make it even smarter because it has following shortcomings in current version:

  • Does not truncate very closely to Max size. Will always be less than 50 bytes from max.
  • If there are only two lines and line of truncating side is huge, even a slight reduction in size will remove the complete content of the huge line, meaning loosing most of the text. This could be taken care of by firsts analyzing the string and then truncating line/character, as required
  • The logic inherently tries to remove lines first, should intelligently decide whether to remove line or chars.

C# : Properties and Serialization

Protected by mikecogh, on Flickr
Protected, a photo by mikecogh on Flickr.

Does your app serialize (on IS or for wire-travelling) model entities to JSON/XML? Did you come across a scenario where you want to ensure that a property is, though serialize-able but should not be settable from the code? For example ID property. Your model class creates this ID internally and it also gets serialized. For it being serialize-able, it is required that the properly is public, but then you expose it to other parts of code as well and make it vulnerable for accidental edits. EditorBrowsableAttribute is not the solution here because of two reasons; one it does not work with the code inside your project, second if it did work, it’s still only hiding from IntelliSense and not stopping you from setting the property in code.
I tackle this scenario in my Nokia Lumia app by having a super-class PersistentEntity and then derive all model classes from PersistentEntity class.
ClassDiagram
PersistentEntity has two properties related to serialization – WriteState and ReadState which are of PersistencyStates enumeration type. PersistencyStates enum has following members – None, WritePending, Queued (because all serialization takes place on BG thread), Writing, Written, Read, and Reading. In case of serializing an entity, as soon as any changes made to the object, the object goes in WritePending, and from there it changes state from Queued to Writing, to Written state. Every other property in derived class which needs to be exposed for serialization only, ensures that in setter sets the value SavingState is “Saving”. If it is not, throw an invalid operation exception with proper message. Let’s have a look at the code.

PersistencyStates enumerator:

    public enum PersistencyStates
    {
        None, WritePending, Queued, Writing, Written, Reading, Read
    }

This is the super class PersistentEntity:

   public class PersistentEntity : ISerializable
    {
        [NonSerialized] //for Silverlight this is IgnoreDataMember attribute
        public PersistencyStates WriteState { get; private set; }
        [NonSerialized] //for Silverlight this is IgnoreDataMember attribute
        public PersistencyStates ReadState { get; private set; }

        #region serialization related methods
        [OnDeserializing]
        public void OnDeSerializingEntity(StreamingContext context)
        {
            this.WriteState = PersistencyStates.Writing;
        }
        [OnDeserialized]
        public void OnDeSerializedEntity(StreamingContext context)
        {
            this.WriteState = PersistencyStates.Written;
            //do something else if required
            this.WriteState = PersistencyStates.None;
        }
        [OnSerializing]
        public void OnSerializingEntity(StreamingContext context)
        {
            this.ReadState = PersistencyStates.Reading;
        }
        [OnSerialized]
        public void OnSerializedEntity(StreamingContext context)
        {
            this.ReadState = PersistencyStates.Read;
        }
        #endregion //serialization related methods


        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            //do nothing;
        }
    }

This is the derived class TestEntity have a property ID which is ensured to update only while serialization:

   class TestEntity : PersistentEntity
    {
        private Guid _id = Guid.NewGuid();
        public Guid ID 
        {
            get 
            {
                return _id;
            }
            set
            {
                if (this.WriteState == PersistencyStates.Writing)
                {
                    _id = value;
                }
                else
                {
                    throw new InvalidOperationException("Cannot set ID from outside", new Exception("MyCompany.MVVM.Model.TestEntity.ID has public setter for the purpose of serialization only. Not designed to be set from outside of the class."))
                }
            }
        }
    }

I hope I could make the intent and implementation clear.

XAML|C# Step By Step : UserControl – Wait Spinner

Waiting by moonux, on Flickr
Waiting, a photo by moonux on Flickr.

Something is cooking in the background? Do not forget to inform your user. A modern, flat, light weight, wait spinner is an animated and prominent way to inform user about running background processes (you would not have long running processes on the UI thread, right? See how to effectively free up UI). You would choose to show this control in that area of the screen to which the information, related to which the BG work is taking place – loading/processing etc, belongs. You may have multiple information points on screen for which background work is running.

For this step-by-step we will create this example:

A practical example of implementation of this spinner is this panorama app there are two wait spinners being used, one in Quick Stopwatch pano, and other in Recent pano. When data related to Quick stopwatch is loading, the wait spinner shows beside the title “Quick”, and when data related to Recent is loading, the wait spinner shows near the pano title “Recent”. This way user is informed about which section of the app is doing something in the background.

WaitSpinnerExample

Don’t have this app on your Windows Phone? Visit here

Let’s go through step-by-step of creating a WaitSpinner UserControl and using it in a page.

Step 1 : Create Solution and Project

  1. Create a project in VS with the name “WaitSpinner”. The solution gets created automatically.
  2. Right click on the solution in Solution Explorer, and choose “Add”>”New Project”.
  3. Select Class Library type project and name it “XAMLControls”.

Step 2 : Create UserControl

  1. Right click on XAMLControls and select “Add”>”New item”.
  2. Choose User Control and name it “UCWaitSpinner”.
  3. A new UCWaitSpinner.xaml and its code behind is created.

Step 3 : Open in Blend

Right click on UCWaitSpinner.xaml and choose to open in Blend. Depending on the version of Visual Studio the view you get might be a little different, but most of the UI will be similar. You will get something like this:
01_OpenUCInBlend

Step 4 : Change the type of Layout control

Change the type of Layout from Grid to ViewBox.
02_ChangeLayoutType

Step 5 : Add a new Grid to Layout ViewBox

  1. Choose Grid from control and right click and drag in XAML design view area.
  2. Update Layout properties; Height and Width to 50, HorizontalAlignment and VerticalAlignment to Stretch.

03_AddGridToLayoutRoot

Step 6 : Add Outer border

  1. Choose Ellipse tool from Toolbox and create a circle in the design area. Don’t worry about size and fill at this point.
  2. Make sure Ellipse is selected.
  3. In Properties.Brushes;
    • Set Fill to “No Brush”.
    • Set Stroke to “PhoneForegroundBrush”.
  4. In Layout section;
    • Set HorizontalAlignment to stretch.
    • Set VerticalAlignment to stretch.
    • Set all margins to 0.

04_CreateACircle

Step 7 : Add axis for hands

  1. Choose Ellipse tool from Toolbox again and create a circle in the middle of XAML design. Don’t bother about size at this point.
  2. Make sure this ellipse is selected.
  3. In Properties.Brushes;
    • Set Fill to “PhoneForegroundBrush”.
    • Set Stroke to “No Brush”.
  4. In Layout section;
    • Set Width and Height to 5.
    • Set HorizontalAlignment to center.
    • Set VerticalAlignment to center.
    • Set all margins to 0.

05_CreateAxisForHands

Step 8 : Add minute and hour hands

  1. Choose Rectangle tool from Toolbox and create a rectangle in the design area. Don’t worry about size and placement at this point.
  2. Rename the [Rectangle] to “MinuteHand”.
  3. Make sure you have MinuteHand selected.
  4. In Properties.Brushes;
    • Set Fill to “PhoneForegroundBrush”.
    • Set Stroke to “No Brush”.
  5. In Layout section;
    • Set Width to 2 and Height to 20.
    • Set HorizontalAlignment to Center.
    • Set VerticalAlignment to Bottom.
    • Set Bottom margin to 25 and all others to 0.
  6. In Properties.Transform;
    • Select Center Point tab.
    • Set X to 0.5.
    • Set Y to 1.
  7. Copy and paste “MinuteHand” control and name it “HourHand”. Keep everything same and change only the Properties.Layout.Height to 13.

06_CreateMinuteHand

Step 9 : Create Storyboard for moving hands

  1. In Objects and Timeline, click on “+” sign to add a new storyboard.
  2. Name the storyboard as “MoveHands”.

07_CreateStoryBoard

Step 10 : Create animation for minute hand

  1. In timeline window slide the marker to 3 second.
  2. Select MinuteHand control.
  3. In Properties.Transform select Rotate tab and set Angle property to 1440.

07b_CreateStoryBoard

Step 11 : Create animation for hour hand

  1. Select HourHand control.
  2. In Properties.Transform select Rotate tab and set Angle property to 360.
  3. c. In timeline windows click on play button to see hands are rotating properly (Hour hand completes 1 rotation and minute hand completes 4 rotations in 3 seconds).

07c_CreateStoryBoard

Step 11B : Follow me on Twitter 😀

Step 12 : Review XAML code

Close Blend and go back to XAML view of UCWaitSpinner in VS. You should see following XAML code:

<UserControl x:Class="XAMLControls.UCWaitSpinner"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="480" d:DesignWidth="480">
	<UserControl.Resources>
		<Storyboard x:Name="MoveHands">
			<DoubleAnimation Duration="0:0:3" To="360" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)" Storyboard.TargetName="HourHand" d:IsOptimized="True"/>
			<DoubleAnimation Duration="0:0:3" To="1440" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)" Storyboard.TargetName="MinuteHand" d:IsOptimized="True"/>
		</Storyboard>
    </UserControl.Resources>

    <Viewbox x:Name="LayoutRoot">
    	<Grid Width="50" Height="50">
    		<Ellipse Margin="0">
    			<Ellipse.Stroke>
    				<SolidColorBrush Color="{StaticResource PhoneForegroundColor}"/>
    			</Ellipse.Stroke>
    		</Ellipse>
    		<Ellipse Margin="0" Width="4" Height="4" HorizontalAlignment="Center" VerticalAlignment="Center">
    			<Ellipse.Fill>
    				<SolidColorBrush Color="{StaticResource PhoneForegroundColor}"/>
    			</Ellipse.Fill>
    		</Ellipse>
    		<Rectangle x:Name="MinuteHand" Height="20" Margin="0,0,0,25" Width="2" StrokeThickness="0" HorizontalAlignment="Center" VerticalAlignment="Bottom" RenderTransformOrigin="0.5,1">
    			<Rectangle.RenderTransform>
    				<CompositeTransform/>
    			</Rectangle.RenderTransform>
    			<Rectangle.Fill>
    				<SolidColorBrush Color="{StaticResource PhoneContrastBackgroundColor}"/>
    			</Rectangle.Fill>
    		</Rectangle>
    		<Rectangle x:Name="HourHand" Height="13" Margin="0,0,0,25" Width="2" StrokeThickness="0" HorizontalAlignment="Center" VerticalAlignment="Bottom" RenderTransformOrigin="0.5,1">
    			<Rectangle.RenderTransform>
    				<CompositeTransform/>
    			</Rectangle.RenderTransform>
    			<Rectangle.Fill>
    				<SolidColorBrush Color="{StaticResource PhoneContrastBackgroundColor}"/>
    			</Rectangle.Fill>
    		</Rectangle>
    	</Grid>
    </Viewbox>
</UserControl>

Step 13 : Add appear disappear animations

Add AppearClock and DisappearClock animations just below MoveHands inside UserControl.Resource, like so:

        <Storyboard x:Name="AppearClock">
            <DoubleAnimation Duration="0:0:0.3" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="LayoutRoot" d:IsOptimized="True"/>
        </Storyboard>
        <Storyboard x:Name="DisappearClock">
            <DoubleAnimation Duration="0:0:2" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="LayoutRoot" d:IsOptimized="True"/>
        </Storyboard>

Step 14 : Update code behind

Open code behind UCWaitSpinner.xaml.cs and add following lines to its constructor:

        public UCWaitSpinner()
        {
            InitializeComponent();
            MoveHands.RepeatBehavior = RepeatBehavior.Forever;
            LayoutRoot.Opacity = 0d;
            DisappearClock.Completed += (object sender, EventArgs e) => { MoveHands.Stop(); };
        }

Step 15 : Add start functionality

Add a public Start method to the class:

        public void Start()
        {
            MoveHands.Stop();
            AppearClock.Begin();
            MoveHands.Begin();
        }

Step 16 : Add stop functionality

Add a public Stop methods to the class:

        public void Stop()
        {
            DisappearClock.Begin();
        }

Step 17 : Build

Build XAMLControls project. If your project builds properly you should see UCWaitSpinner listed in your Toolbox in XAML Controls.

Step 18 : Add spinner to form

Open MainPage.xaml from the main project WaitSpinner and drag UCWaitSpinner from the Toolbox to the page. Open MainPage.xaml in code view and your will find the newly added control in ContentPanel:

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <my:UCWaitSpinner/>
        </Grid>

Step 19 : Edit control properties

In MainPage.xaml name UCWaitSpinner control as “waitSpinner”, add Height and Width properties with a value of 120 in both, and wrap the control in a StackPanel:

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <StackPanel>
                <my:UCWaitSpinner x:Name="waitSpinner" Height="120" Width="120" />
            </StackPanel>
        </Grid>

Step 20 : Add buttons to control test

Add two buttons, just below WaitSpinner, Start and Stop with Click handlers to control WaitSpinner:

        <my:UCWaitSpinner x:Name="waitSpinner" Height="120" Width="120" />
        <Button x:Name="buttonStart" Content="Start" Click="buttonStart_Click"/>
        <Button x:Name="buttonStop" Content="Stop"  Click="buttonStop_Click"/>

Step 21 : Write code in click handlers

Open MainPage.xaml.cs and call Start and Stop of WaitSpinner in buttons’ click handlers:

        private void buttonStart_Click(object sender, RoutedEventArgs e)
        {
            waitSpinner.Start();
        }

        private void buttonStop_Click(object sender, RoutedEventArgs e)
        {
            waitSpinner.Stop();
        }

You can run your code and click on Start button to start spinner. Click on Stop button and spinner will slowly fade out.

Let’s see the example code to integrate the control with background processes.

Make following changes to MainPage.xaml’s ContentPanel control:

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <StackPanel>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition/>
                        <ColumnDefinition/>
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Column="0" x:Name="textBlockSeconds" Text="..."/>
                    <my:UCWaitSpinner Grid.Column="1" x:Name="waitSpinner2" Height="90" Width="90" />
                </Grid>
                <my:UCWaitSpinner x:Name="waitSpinner" Height="120" Width="120" />
                <Button x:Name="buttonStart" Content="Start" Click="buttonStart_Click"/>
                <Button x:Name="buttonStop" Content="Stop"  Click="buttonStop_Click"/>
                <Button x:Name="buttonBackground" Content="Background" Click="buttonBackground_Click"/>
            </StackPanel>
        </Grid>

And add following code to the code behind MainPage.xaml.cs:

    public partial class MainPage : PhoneApplicationPage
    {
        // Constructor
        Thread bgThread;
        public MainPage()
        {
            InitializeComponent();
            bgThread = new Thread(new ThreadStart(() => 
            {
                Dispatcher.BeginInvoke(new Action(() => { waitSpinner2.Start(); }));
                for (int cnt = 0; cnt < 5; cnt++)
                {
                    Dispatcher.BeginInvoke(new Action(() => { textBlockSeconds.Text = string.Format("Step - {0}/4", cnt); }));
                    Thread.CurrentThread.Join(2000);
                }
                Dispatcher.BeginInvoke(new Action(() => { waitSpinner2.Stop(); }));
            }));
        }

        private void buttonStart_Click(object sender, RoutedEventArgs e)
        {
            waitSpinner.Start();
        }

        private void buttonStop_Click(object sender, RoutedEventArgs e)
        {
            waitSpinner.Stop();
        }

        private void buttonBackground_Click(object sender, RoutedEventArgs e)
        {
            buttonBackground.IsEnabled = false;
            bgThread.Start();
        }
    }

F5. You should see something like this:

Download entire code here.

C#|XAML : ListBox – Search, Filter, and Highlight (3/3)

Highlight colors. by pasukaru76, on Flickr
Highlight colors., a photo by pasukaru76 on Flickr.

In part 1  and part 2 we set up our ListBox and search TextBox in MainPage.XAML and filtered the list on-the-fly for the text entered in the text box. To see search/filter/highlight code in action in a published app, you can download my app for free.

After having filtered the list, in this post we will add code to highlight the searched text in each field of the items. The highlighted text will be in current accent color on the device, italicized, and underlined.

Let’s open MainPage.xaml.cs and add two new fields at MainPage class level:

        EventHandler _listBoxItemsRearrangedHandler;
        bool    _trapListBoxLayoutUpdate = true;

…and in the constructor initialize the handler:

            _listBoxItemsRearrangedHandler = new EventHandler(listBoxItems_Rearranged);

In the private method prepareFilteredList, we created in Part 2, set the _trapListBoxLayoutUpdate flag and also start listening to LayoutUpdated event of listBoxTextItems:

            _trapListBoxLayoutUpdate = true;
            listBoxTextItems.LayoutUpdated -= new EventHandler(_listBoxItemsRearrangedHandler);
            listBoxTextItems.LayoutUpdated += new EventHandler(_listBoxItemsRearrangedHandler);

Add following two methods for the core highlighting logic:

        void listBoxItems_Rearranged(object sender, EventArgs e)
        {
            if (_trapListBoxLayoutUpdate)
            {
                foreach (var ob in listBoxTextItems.Items)
                {
                    ListBoxItem lbi = listBoxTextItems.ItemContainerGenerator.ContainerFromItem(ob) as ListBoxItem;
                    if (lbi != null)
                    {
                        IEnumerable<TextBlock> _allTextBlocks = ViewHelpers.GetChildrenByType<TextBlock>(VisualTreeHelper.GetChild(lbi, 0));
                        foreach (TextBlock _txtBlock in _allTextBlocks)
                        {
                            if (
                                (
                                _txtBlock.Name == "templateTextBlockName" ||
                                _txtBlock.Name == "templateTextBlockNote" ||
                                _txtBlock.Name == "templateTextBlockAdd"
                                ) &&
                                _txtBlock.Text.ToUpper().Contains(textBoxSearch.Text.ToUpper())
                                )
                            {
                                HightlightText(_txtBlock, textBoxSearch.Text);
                            }
                        }
                    }
                }
                _trapListBoxLayoutUpdate = false;
            }
        }
        public static void HightlightText(TextBlock textBlockTarget, string highlightedText)
        {

            string Text = textBlockTarget.Text;
            textBlockTarget.Inlines.Clear();
            int _indexOfHighlightedTextInTarget = Text.ToUpper().IndexOf(highlightedText.ToUpper());
            Color highlightColor = (Color)Application.Current.Resources["PhoneAccentColor"];
            Run r = new Run();
            r.Text = Text.Substring(0, _indexOfHighlightedTextInTarget);
            textBlockTarget.Inlines.Add(r);


            r = new Run();
            r.Text = highlightedText;
            r.FontWeight = FontWeights.Bold;
            r.FontStyle = FontStyles.Italic;
            r.TextDecorations = TextDecorations.Underline;
            r.Foreground = new SolidColorBrush(highlightColor);
            textBlockTarget.Inlines.Add(r);

            r = new Run();
            r.Text = Text.Substring(_indexOfHighlightedTextInTarget + highlightedText.Length, Text.Length - (_indexOfHighlightedTextInTarget + highlightedText.Length));
            textBlockTarget.Inlines.Add(r);
        }

F5 and when the form is up, type Bill in the text box. You will notice as you are typing list is filtering and the text being typed in the text box is getting highlighted in different fields of the items in the ListBox.

highlight

A more extensive implementation can be found in this app.

Hope you find this code useful.

Happy searching/filtering/highlighting 😀

C#|XAML : ListBox – Search, Filter, and Highlight (2/3)

Filter by Joe Edwards, on Flickr
Filter, a photo by Joe Edwards on Flickr.

In part 1 we set up our ListBox and search TextBox in MainPage.XAML. We also created the ViewModel class which will be shown in the ListBox. You can download my app for free which has the complete working filter/search/highlight function.

In this post we will add functionality to filter our ListBox items on the basis of text entered in TextBox. We will filter the list on the fly without any query. To achieve this we will utilize filter event of CollectionViewSource. We will also create a field in Profile class to concatenate different properties which are going to participate in search.

Add new property to Profile class like so:

        public string SearchText { get { return string.Format("{0}|{1}|{2}", Name, Address, Note); } }

Update the code behind MainPage.xaml.cs to add a filter event handler. This is how the complete code of MainPage class will look like:

    public partial class MainPage : PhoneApplicationPage
    {
        ObservableCollection<Profile> _infoList = new ObservableCollection<Profile>();
        FilterEventHandler _searchFilter;

        // Constructor
        public MainPage()
        {
            InitializeComponent();

            _infoList.Add(new Profile("A Kejriwal", "New Delhi, India", "I am common man A"));
            _infoList.Add(new Profile("Bill Gates", "Microsoft One", "I am not a common man"));
            _infoList.Add(new Profile("Bill Burr", "Comedy Central", "Don't say there is no reason"));
            _infoList.Add(new Profile("Kartavya Sharma", "Street dhimka", "What do you mean?"));
            _infoList.Add(new Profile("Louis CK", "HBO One Night", "Bill curses a lot in comedy"));
            _infoList.Add(new Profile("Sanjay Sharma", "Street falana", "What do you mean?"));
            _infoList.Add(new Profile("Z Kejriwal", "New Delhi, India", "Don't underestimate the power"));

            _searchFilter = new FilterEventHandler(onSearchResultsFiltering);

            textListViewSource.Source = null;
            textListViewSource.Source = _infoList;
            textListViewSource.Filter += _searchFilter;
            listBoxTextItems.DataContext = _infoList;
        }

        private void onSearchResultsFiltering(object sender, FilterEventArgs e)
        {
            Profile _info = e.Item as Profile;
            if (_info != null)
            {
                if (_info.SearchText.ToUpper().Contains(String.Format("{0}", textBoxSearch.Text).ToUpper()))
                {
                    e.Accepted = true;
                }
                else
                {
                    e.Accepted = false;
                }
            }
        }
    }

Next, we want our TextBox to initiate filtration of the ListBox items as soon as text is changed by user. To achieve this behavior, we will trap KeyUp event of TextBox. Let’s update XAML to add the event handler.

<TextBox Grid.Row="0" x:Name="textBoxSearch" KeyUp="textBoxSearch_KeyUp"/>

As we have the event handler code inserted by VS in the code behind, let’s update it to refresh our ListBox with latest filtered list:

        private void textBoxSearch_KeyUp(object sender, KeyEventArgs e)
        {
            Dispatcher.BeginInvoke(new Action(prepareFilteredList));
        }
        private void prepareFilteredList()
        {
            textListViewSource.View.Refresh();
        }

We are ready! F5. Type ‘Bill’ in TextBox. You will see that the list gets filtered on the fly, while you type. Filtered list should look like this :
FilteredList

In the next part of the series, we will see how to highlight the searched text in the fields in ListBox.

To be continued…(Part 3)

C#|XAML : ListBox – Search, Filter, and Highlight (1/3)

C#|XAML : ListBox – Search, Filter, and Highlight (1/3)

In this 3 part series we will go through c#/XAML code to setup Listbox with multiple rows of information having ability to search, filter and highlight the text in searched items. To see the actual running code of this ListBox in live app, you can check my app. The topics of different parts in this series are as follows:

  • Part 1: Set-up form with TextBox and ListBox with example model class
  • Part 2: Add search and filter ability
  • Part 3: Highlight searched text

Setup Test XAML Form

This is our default MainPage.XAML. We will add a TextBox control and a ListBox control to this page. TextBox control is where we will input the text to be searched in the ListBox items. ListBox will show items. Each item has three information fields. These fields are: Name, Address, and Note. Let’s first update the XAML created by Studio.

Replace the default “ContentPanel” control with following Grid:

        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Grid.RowDefinitions>
                <RowDefinition Height="80"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <TextBox Grid.Row="0" x:Name="textBoxSearch" KeyUp="textBoxSearch_KeyUp"/>
            <ListBox Grid.Row="1" x:Name="listBoxTextItems"></ListBox>
        </Grid>

Create ViewModel Class

The class which feeds data to the ListBox is Profile and contains three basic properties : Name, Address, and Note. For the sake of keeping this example simple, let’s write this class in the code-behind, MainPage.xaml.cs (please note, in real world, ViewModel classes do not go in the code-behinds and they usually have mechanism to broadcast change messages to UI. To keep the focus on the subject in hand, we are only writing just the essential code).

    public class Profile
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public string Note { get; set; }
        public Profile(string name, string add, string note)
        {
            Name = name;
            Address = add;
            Note = note;
        }
    }

Create List and connect View and ViewModel

Let’s first update MainPage.XAML to add CollectionViewSource to its resources and bind it to the ListBox. We need CollectionViewSource to filter our data in the view.

    <phone:PhoneApplicationPage.Resources>
        <CollectionViewSource x:Name="textListViewSource">
        </CollectionViewSource>
    </phone:PhoneApplicationPage.Resources>

Update the ListBox definition to add the CollectionViewSource:

            <ListBox Grid.Row="1" x:Name="listBoxTextItems" ItemsSource="{Binding Source={StaticResource textListViewSource}}">

We also want our ListBox to show these items in different sizes and colors so that three different rows in each item can be differentiated visually. So, we will add a visual template for ListItem and assign it to the ListBox.

The style definition will go in the Resources section:

        <Style x:Key="styleInfoTextListBox" TargetType="ListBoxItem">
            <Setter Property="HorizontalAlignment" Value="Left" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <Grid x:Name="gridDataTemplate" Margin="15,5,5,5">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
                            <TextBlock Grid.Row="0" x:Name="templateTextBlockName" Text="{Binding Name}" FontFamily="Segoe WP Black" FontSize="{StaticResource PhoneFontSizeExtraLarge}" Foreground="White"/>
                            <TextBlock Grid.Row="1" x:Name="templateTextBlockAdd" Text="{Binding Address}" FontFamily="Segoe WP" FontSize="{StaticResource PhoneFontSizeLarge}" Foreground="White" Opacity="0.8"/>
                            <TextBlock Grid.Row="2" x:Name="templateTextBlockNote" Text="{Binding Note}" FontFamily="Segoe WP Light" FontSize="{StaticResource PhoneFontSizeNormal}" Foreground="White" Opacity="0.8"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

Update the ListBox definition one last time to apply the style on ListItems to add the CollectionViewSource:

<ListBox Grid.Row="1" x:Name="listBoxTextItems" ItemsSource="{Binding Source={StaticResource textListViewSource}}" ItemContainerStyle="{StaticResource styleInfoTextListBox}">

Our ListBox is ready to show the data. Now let’s switch back to MainPage.xaml.cs. We will create an ObservableCollection of Profile type and add some example data to it. We will write this code in MainPage.xaml.cs. Also in the constructor of our page we will set CollectionViewSource’s source and ListBox’s DataContext to connect our list with the data. Our MainPage.xaml.cs will look like this:

    public partial class MainPage : PhoneApplicationPage
    {
        ObservableCollection<Profile> _infoList = new ObservableCollection<Profile>();
        // Constructor
        public MainPage()
        {
            InitializeComponent();

            _infoList.Add(new Profile("A Kejriwal", "New Delhi, India", "I am common man A"));
            _infoList.Add(new Profile("Bill Gates", "One Microsoft, Redmond", "I am not a common man"));
            _infoList.Add(new Profile("Bill Burr", "Comedy Central", "Don't say there is no reason"));
            _infoList.Add(new Profile("Kartavya Sharma", "Street dhimka", "What do you mean?"));
            _infoList.Add(new Profile("Louis CK", "HBO One Night", "Bill curses a lot in comedy"));
            _infoList.Add(new Profile("Sanjay Sharma", "Street falana", "What do you mean?"));
            _infoList.Add(new Profile("Z Kejriwal", "New Delhi, India", "Don't underestimate the power"));

            textListViewSource.Source = _infoList;
            listBoxTextItems.DataContext = _infoList;
        }
    }

Let’s F5 our form. You should see this on your emulator:
List

In next post we will write code to respond to search query in TextBox and filter data in ListBox.

To be contd… Part 2

C#|.NET : Generic Concurrent Queue (6/6)

... by g corallo, on Flickr
, a photo by g corallo on Flickr.

Visit these posts for Part 1, Part 2, Part 3, Part 4, Part 5, and real life implementation

In this concluding post we will make some changes to further separate some concerns and see multiple queues in action. First we will take the queue initialization to higher level in availability and define the queues in our top level class, i.e. App.xaml.cs. This way our queues are available everywhere in the application. We will move out background enqueue-ing to class level and expose it through a  method. This is to encapsulate the behavior to self-enqueue-ing in the class itself. So the user of the class does not have to know anything about the queue, they could simply call the class’ method and the class will queue itself for background work. Let’s start.
First, let’s modify the code of TypeOneTask class we created in Part 5, and encapsulate enqueue behavior in the class itself. We will introduce a new public method QueueInForBackgroundWork:

        public void QueueInForBackgroundWork()
        {
            Debug.WriteLine("UI Thread : {0} enqueue starting", this.Name);
            App.t1Queue.Process(this, true, false);
            Debug.WriteLine("UI Thread : {0} enqueue finished", this.Name);
        }

Before going to consumption code for this method in our main page’s code behind, let’s first set-up TypeTwoTask class and a new queue for the same. We will create a new class file TaskTwoQueue.cs and write code in this file. Most of the code in these classes is similar to what we created in Part5, so I will write all the code in one code block:

namespace TaskQueue
{
    public class TaskTwoQueue : ConcurrentQueue<TypeTwoTask>
    {
        #region queue implementationsc
        TypeTwoTaskEqualityComparer _itemEqualityComparer = new TypeTwoTaskEqualityComparer();
        public override bool IsQueueAlive
        {
            get
            {
                return base.IsQueueAlive;
            }
        }
        public override IEqualityComparer<TypeTwoTask> QueueItemEualityComparer
        {
            get
            {
                return _itemEqualityComparer;
            }
        }
        public override bool IsQueueAvailableForEnqueue()
        {
            if (this.Count > 10)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        protected override void ProcessRequest(TypeTwoTask taskRequest, bool Async)
        {
            taskRequest.Process();
        }
        public override void Exit(bool discardPendingRequests)
        {
            base.Exit(discardPendingRequests);
        }
        public override void DoWhenQueueGetsEmpty()
        {
            //doing nothing
        }
        #endregion
    }

    public class TypeTwoTask
    {
        Random testWait = new Random();
        public string Name { get; set; }
        public event EventHandler BackgroundProcessFinished;
        public TypeTwoTask(string name)
        {
            Name = name;
        }
        public void Process()
        {
            DateTime _st = DateTime.Now;
            Debug.WriteLine("BG Thread : Task {0} starting @ {1}", Name, _st.ToString("hh:mm:ss.fff"));
            Thread.CurrentThread.Join(testWait.Next(735, 1923));
            Debug.WriteLine("BG Thread : Task {0} Ended @ {1}", Name, DateTime.Now.ToString("hh:mm:ss.fff"));
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                if (BackgroundProcessFinished != null)
                {
                    BackgroundProcessFinished(this, new EventArgs());
                }
            });
        }
        public void QueueInForBackgroundWork()
        {
            Debug.WriteLine("UI Thread : {0} enqueue starting", this.Name);
            App.t2Queue.Process(this, true, false);
            Debug.WriteLine("UI Thread : {0} enqueue finished", this.Name);
        }
    }

    public class TypeTwoTaskEqualityComparer : IEqualityComparer<TypeTwoTask>
    {
        public bool Equals(TypeTwoTask A, TypeTwoTask B)
        {
            if (A != null && B != null)
            {
                return A.Name == B.Name;
            }
            else
            {
                return false;
            }
        }
        public int GetHashCode(TypeTwoTask itm)
        {
            return itm.GetHashCode();
        }
    }

}

We are ready with our second queue. We will introduce this queue in our application at the application level. In app.xaml.cs we will define both the queues like so (mind that both the queues are static):

    public partial class App : Application
    {
        public static TaskOneQueue t1Queue = new TaskOneQueue();
        public static TaskTwoQueue t2Queue = new TaskTwoQueue();
    }

The final user of our two classes, the main page, now, does not need to know about the queue (for previous code see part 5). It will only define the fields of appropriate task type, and call its QueuInForBackgroundWork as and when required. To demonstrate this behavior, we will modify MainPage.xaml.cs. We will first define 3 tasks of both the types at the page level. We will then have event handlers for both the types of the tasks to have informed about the completion of the task on UI thread. Button_click enqueues TypeOneTask in the queue by calling QueueInForBackgroundWork method and buttonDummy1_Click does the same for TypeTwoTask. Here is the code:

    public partial class MainPage : PhoneApplicationPage
    {
        TypeOneTask _t1 = new TypeOneTask("Type1 Task-1");
        TypeOneTask _t2 = new TypeOneTask("Type1 Task-2");
        TypeOneTask _t3 = new TypeOneTask("Type1 Task-3");

        TypeTwoTask _t4 = new TypeTwoTask("Type2 Task-4");
        TypeTwoTask _t5 = new TypeTwoTask("Type2 Task-5");
        TypeTwoTask _t6 = new TypeTwoTask("Type2 Task-6");

        public MainPage()
        {
            InitializeComponent();
            this.BackKeyPress += new EventHandler<System.ComponentModel.CancelEventArgs>(MainPage_BackKeyPress);
            _t2.BackgroundProcessFinished += (object sender, EventArgs e) => { Debug.WriteLine("UI Thread : TypeOneTask _t1 finished!"); };
            _t3.BackgroundProcessFinished += (object sender, EventArgs e) => { Debug.WriteLine("UI Thread : TypeOneTask _t2 finished!"); };
            _t5.BackgroundProcessFinished += (object sender, EventArgs e) => { Debug.WriteLine("UI Thread : TypeTwoTask _t5 finished!"); };
            _t6.BackgroundProcessFinished += (object sender, EventArgs e) => { Debug.WriteLine("UI Thread : TypeTwoTask _t6 finished!"); };
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            _t1.QueueInForBackgroundWork();
            _t2.QueueInForBackgroundWork();
            _t3.QueueInForBackgroundWork();
        }
        private void buttonDummy1_Click(object sender, RoutedEventArgs e)
        {
            _t4.QueueInForBackgroundWork();
            _t5.QueueInForBackgroundWork();
            _t6.QueueInForBackgroundWork();
        }

        private void buttonDummy2_Click(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("UI Thread : Dummy button 2 clicked!");
        }

    }

When you run the the app in debug mode, you get three buttons – Button1, dummy 1, and dummy 2, same as we had in part 5. This time Button1 and dummy 1 both enqueue tasks and dummy 2 is just to demonstrate that UI thread is free. Now, with 1-2 seconds delay, click on these three buttons top to bottom. You will get following log in your Debug output:

Output.Debug

UI Thread : Type1 Task-1 enqueue starting
UI Thread : Type1 Task-1 enqueue finished
UI Thread : Type1 Task-2 enqueue starting
UI Thread : Type1 Task-2 enqueue finished
UI Thread : Type1 Task-3 enqueue starting
UI Thread : Type1 Task-3 enqueue finished
BG Thread : Task Type1 Task-1 starting @ 12:29:35.530
UI Thread : Type2 Task-4 enqueue starting
UI Thread : Type2 Task-4 enqueue finished
BG Thread : Task Type2 Task-4 starting @ 12:29:36.502
UI Thread : Type2 Task-5 enqueue starting
UI Thread : Type2 Task-5 enqueue finished
UI Thread : Type2 Task-6 enqueue starting
UI Thread : Type2 Task-6 enqueue finished
BG Thread : Task Type1 Task-1 Ended @ 12:29:37.403
BG Thread : Task Type1 Task-2 starting @ 12:29:37.413
BG Thread : Task Type2 Task-4 Ended @ 12:29:37.575
BG Thread : Task Type2 Task-5 starting @ 12:29:37.581
UI Thread : Dummy button 2 clicked!
BG Thread : Task Type1 Task-2 Ended @ 12:29:38.500
BG Thread : Task Type1 Task-3 starting @ 12:29:38.506
UI Thread : TypeOneTask _t1 finished!
BG Thread : Task Type2 Task-5 Ended @ 12:29:38.635
BG Thread : Task Type2 Task-6 starting @ 12:29:38.642
UI Thread : TypeTwoTask _t5 finished!
BG Thread : Task Type1 Task-3 Ended @ 12:29:39.576
UI Thread : TypeOneTask _t2 finished!
BG Thread : Task Type2 Task-6 Ended @ 12:29:39.691
UI Thread : TypeTwoTask _t6 finished!

The analysis of this output shows that Type1 tasks were enqueued first, because I clicked Button1 first, and as soon as all three tasks are enqueued UI thread was freed. Also, “Task Type1 Task-1” started its BG work. Because UI was free, after two seconds, I clicked Dummy 1 button which enqueued all the three tasks of TypeTwoTask in its queue. Both these queues are working on their own background threads. UI thread is completely free. When tasks get over UI gets a message.

To summarize, Generic Concurrent Queue has following characteristics:

  • Generic and abstract, to be inherited to implement for any type.
  • Process requests can be queued up for BG thread.
  • Has a single lazy-init BG thread.
  • Supports sync and async requests.
  • By supplying a sync process request, you can stop other processes in queue and have sync request process first. Queue resumes automatically after the sync task is over.
  • Queue can be paused and restarted as and when required.
  • Queue can be exited | killed as and when required.
  • Inherited class defines rules for Queue capacity.
  • Inherited class defines rules for process request duplicate value.
  • Uses basic lock/wait/pulse mechanism, so compatible with almost all variants of .NET

Please feel free to comment. Hope you find this concurrent queue useful.

C#|.NET : Generic Concurrent Queue (5/6)

A bench by Myxi, on Flickr
A bench, a photo by Myxi on Flickr.

Visit these posts for Part 1, Part 2, Part 3, Part 4, and implementation!

The real magic starts now…

First of all we will create an example task class (could be any model/view-model class), which is our real world class with the code to be processed on BG thread. The class encapsulates its own behavior.

    public class TypeOneTask
    {
        Random _testWait = new Random();
        public string Name { get; set; }
        public event EventHandler BackgroundProcessFinished;
        public TypeOneTask(string name)
        {
            Name = name;
        }
        public void Process()
        {
            DateTime _st = DateTime.Now;
            Debug.WriteLine("BG Thread : Task {0} Started @ {1}", Name, _st.ToString("hh:mm:ss.fff"));
            Thread.CurrentThread.Join(_testWait.Next(735, 1923));
            Debug.WriteLine("BG Thread : Task {0} Ended @ {1}", Name, DateTime.Now.ToString("hh:mm:ss.fff"));
            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
                if (BackgroundProcessFinished != null)
                {
                    BackgroundProcessFinished(this, new EventArgs());
                }
            });
        }
    }

This is a simple example class with a Name property and Process method. The process method has Debug messages and Thread.Join to simulate process. On completion of the process, the method fires an event on the dispatcher thread, i.e. the UI thread.

We will also need an equality comparer, to avoid duplicate objects being queued for process. Currently we will simply compare the reference, but equating could be extended in real world classes.

    public class TypeOneTaskEqualityComparer : IEqualityComparer<TypeOneTask>
    {
        public bool Equals(TypeOneTask A, TypeOneTask B)
        {
            if (A != null && B != null)
            {
                return A == B;
            }
            else
            {
                return false;
            }
        }
        public int GetHashCode(TypeOneTask itm)
        {
            return itm.GetHashCode();
        }
    }

Now comes the implementation of our generic ConcurrentQueue class by inheriting in a new class named TaskOneQueue. We will implement the required method/properties in the derived class and in the ProcessRequest method, which is protected and called from the base class, we will call the TypeOneTask’s process method. This is the actual process which runs on the background thread. So here is the code for our TaskOneQueue:

   public class TaskOneQueue : ConcurrentQueue<TypeOneTask>
    {
        #region queue implementationsc
        TypeOneTaskEqualityComparer _itemEqualityComparer = new TypeOneTaskEqualityComparer();
        public override bool IsQueueAlive
        {
            get
            {
                return base.IsQueueAlive;
            }
        }
        public override IEqualityComparer<TypeOneTask> QueueItemEualityComparer
        {
            get
            {
                return _itemEqualityComparer;
            }
        }
        public override bool IsQueueAvailableForEnqueue()
        {
            if (this.Count > 20)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        protected override void ProcessRequest(TypeOneTask taskRequest, bool Async)
        {
            taskRequest.Process();
        }
        public override void Exit(bool discardPendingRequests)
        {
            base.Exit(discardPendingRequests);
        }
        public override void DoWhenQueueGetsEmpty()
        {
            //doing nothing
        }
        #endregion
    }

We have our structure taken care of. Let’s put this things in a example form to see how things work. We will create a simple Windows Phone project and in the default MainPage.xaml’s ContentPanel element, we will put a StackPanel containing three buttons:

      <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <StackPanel>
        	    <Button Content="Button" Height="69" Margin="110,49,127,0" VerticalAlignment="Top" Click="Button_Click"/>
                <Button Name="buttonDummy1" Content="Dummy 1" Height="69" Margin="110,49,127,0" VerticalAlignment="Top" Click="buttonDummy1_Click" />
                <Button Name="buttonDummy2" Content="Dummy 2" Height="69" Margin="110,49,127,0" VerticalAlignment="Top"  Click="buttonDummy2_Click"/>
            </StackPanel>
        </Grid>

Code behind for this form looks like this:

   public partial class MainPage : PhoneApplicationPage
    {
        TaskOneQueue t1Queue = new TaskOneQueue();
        // Constructor
        public MainPage()
        {
            InitializeComponent();
            this.BackKeyPress += new EventHandler<System.ComponentModel.CancelEventArgs>(MainPage_BackKeyPress);
        }

        void MainPage_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
        {
            t1Queue.Exit(true);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            TypeOneTask _t1 = new TypeOneTask("Type1 Task - 1");
            TypeOneTask _t2 = new TypeOneTask("Type1 Task - 2");
            TypeOneTask _t3 = new TypeOneTask("Type1 Task - 3");
            _t2.BackgroundProcessFinished += new EventHandler(_t2_BackgroundProcessFinished);
            _t3.BackgroundProcessFinished += new EventHandler(_t3_BackgroundProcessFinished);

            Debug.WriteLine("UI Thread : Task enqueue start");
            t1Queue.Process(_t1, true, false);
            t1Queue.Process(_t2, true, false);
            t1Queue.Process(_t3, true, false);
            Debug.WriteLine("UI Thread : Task enqueue finished. Enqueued Type1 tasks 1, 2, and 3. UI thread is free");
        }

        void _t3_BackgroundProcessFinished(object sender, EventArgs e)
        {
            Debug.WriteLine("UI Thread : All tasks are over!");
        }

        void _t2_BackgroundProcessFinished(object sender, EventArgs e)
        {
            Debug.WriteLine("UI Thread : Task two has finished and UI thread got the message!");
        }

        private void buttonDummy1_Click(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("UI Thread : Dummy button 1 clicked!");
        }

        private void buttonDummy2_Click(object sender, RoutedEventArgs e)
        {
            Debug.WriteLine("UI Thread : Dummy button 2 clicked!");
        }

    }

In the code above, we have defined TaskOneQueu type object – t1Queue. In Button_Click event handler we are enqueuing three TypeOneTasks and at the start and end of enqueuing, sending output to Debug window. This shows that UI thread gets free after enqueuing the tasks. This is further demonstrated in the click handlers of the buttonDummy1_Click and buttonDummy2_Click, which you can manually click at run time to see that UI thread is free and task processes are happening in the background. When we run this form in Debug mode, and click the first button and then subsequently Button 2 and Button 3 at 1-2 seconds apart, we get following output from Debug. You can see when UI thread gets free and first TypeOneTask starts processing. In the mean time the two dummy buttons are also clicked and their click events got registered successfully without having any impact on the background processes.

Output.Debug
UI Thread : Task enqueue start
UI Thread : Task enqueue finished. Enqueued Type1 tasks 1, 2, and 3. UI thread is free
BG Thread : Task Type1 Task - 1 Started @ 04:39:24.483
UI Thread : Dummy button 1 clicked!
BG Thread : Task Type1 Task - 1 Ended @ 04:39:26.436
BG Thread : Task Type1 Task - 2 Started @ 04:39:26.442
UI Thread : Dummy button 2 clicked!
BG Thread : Task Type1 Task - 2 Ended @ 04:39:28.258
BG Thread : Task Type1 Task - 3 Started @ 04:39:28.264
UI Thread : Task two has finished and UI thread got the message!
BG Thread : Task Type1 Task - 3 Ended @ 04:39:30.090
UI Thread : All tasks are over!

In the last post we will create one more queue and run multiple queues simultaneously to see things in action.

continued…part 6

C#|.NET : Generic Concurrent Queue (4/6)

Visit these posts for Part 1, Part 2 & Part 3.

My app has the implementation of this queue. Let’s look at the code of some of the important public and private methods in the class:

Reset method locks the _queueLocker object, which is functioning as Mutex, making sure only a single operation executes on the queue:

        /// <summary>
        /// Discards all pending requests and deletes all requests in queue, queue is ready for new items to be enqued after this.
        /// </summary>
        public virtual void Reset()
        {
            lock (_queueLocker)
            {
                RequestQueue.Clear();
            }
        }

Exit method exits the queue. If discardPendingRequests is true, queue exits discarding any pending request. Exit does not ensure an immediate termination of queue. If a task is in process, first the task will complete and then remaining task will be discarded.

        /// <summary>
        /// Exits queue.
        /// </summary>
        /// <param name="discardPendingRequests"></param>
        public virtual void Exit(bool discardPendingRequests)
        {
            _exitWhenQueueIsEmpty = true;
            _discardPendingRequests = discardPendingRequests;
            _closeQueue = discardPendingRequests;
            lock (_queueLocker)
            {
                Monitor.Pulse(_queueLocker);
            }
        }

HaltQueueProcess halts the queue and ProceedQueueProcess brings the queue out of the halt.

        /// <summary>
        /// Halts the queue process. 
        /// </summary>
        public virtual void HaltQueueProces()
        {
            _haltQueue = true;
        }
        /// <summary>
        /// Call if queue is halted and you want to restart it.
        /// </summary>
        public void ProceedQueueProcess()
        {
            lock (_queueLocker)
            {
                _haltQueue = false;
                Monitor.Pulse(_queueLocker);
            }
        }

Process method is called to enqueue/process a task request. If Async parameter is true, task is enqueued and calling thread is freed. If Async parameter is false, other tasks in the queue are suspended and this new task is executed. The task executes on the calling thread and not on the background thread. isRecursive is usually used by those process requests which are called from inside the process queue. If isRecursive is true, the request is automatically considered as synched request.

        /// <summary>
        /// Processes the request.
        /// </summary>
        /// <param name="request">The request to process</param>
        /// <param name="async">Is the request Async</param>
        /// <param name="isRecurssive">Is the request Recursive, meaning - was this method called from the Process itself. See example in notes.</param>
        /// <remarks>
        ///  Example 
        ///  Entity.Save 
        ///    `--~IsolatedStorageRequestQueue.Process~-----. 
        ///         `--~Entity.OnEntitySaved     |
        ///             `--~Entity.ContainedEntities.Save -'
        ///             
        /// </remarks>
        public void Process(T request, bool async, bool isRecurssive)
        {
            if (_closeQueue || request == null) return;
            if (Async && (_processThread == null || !_processThread.IsAlive))
            {
                _processThread = new Thread(new ThreadStart(processQueue));
                _processThread.Name = "Process thread @ " + Environment.TickCount.ToString();
                _processThread.Start();
            }
            if (Async && !isRecursive)
            {
                enqueueRequest(request);
            }
            else
            {
                if (!isRecurssive)
                {
                    _synchedRequestStatus = RequestStatus.Pending;
                    lock (_processLocker)
                    {
                        _synchedRequestStatus = RequestStatus.InProcess;
                        ProcessRequest(request, false);
                        _synchedRequestStatus = RequestStatus.Finished;
                        Monitor.Pulse(_processLocker);
                    }
                }
                else
                {
                    ProcessRequest(request, false);
                }
            }
        }

Private enqueuRequest checks if queue is full (determined by abstract method IsQueueAvailableForEnqueue, which is to be implemented in the derived class.), if it is, it waits for queue to be available for enqueue. Also, if the request is checked for duplicate entry before enqueue.

        private void enqueueRequest(T request)
        {
            while (QueueIsFull)
            {
                lock (_waitForQueueToBeAvailableForEnqueue) Monitor.Wait(_waitForQueueToBeAvailableForEnqueue, 3000);
                QueueIsFull = !IsQueueAvailableForEnqueue();
            }
            lock (_queueLocker)
            {
                if (!RequestQueue.Contains(request, QueueItemEualityComparer))
                {
                    RequestQueue.Enqueue(request);
                    QueueIsFull = !IsQueueAvailableForEnqueue();
                }
                Monitor.Pulse(_queueLocker);
            }
        }

Private method processQueue is the internal method which takes care of task dequeue. All the tasks in the queue are processed in FIFO priority. This method and the task run on background thread.

        private void processQueue()
        {
            _isQueueAlive = true;
            while (true)
            {
                T RequestToProcess = default(T);
                bool processthisRequest = false;
                if (RequestQueue.Count == 0)
                {
                    this.DoWhenQueueGetsEmpty();
                    lock (WaitTillQueueGetsEmpty)
                    {
                        Monitor.Pulse(WaitTillQueueGetsEmpty);
                    }
                    lock (WaitTillQueueEmptiesOrHalted)
                    {
                        Monitor.Pulse(WaitTillQueueEmptiesOrHalted);
                    }
                }
                if (Monitor.TryEnter(_queueLocker, 1000))
                {
                    try
                    {
                        while (_haltQueue || (RequestQueue.Count == 0 && !_exitWhenQueueIsEmpty && !_discardPendingRequests))
                        {
                            Monitor.Wait(_queueLocker, 7000);
                            if (_haltQueue)
                            {
                                lock (WaitTillQueueEmptiesOrHalted)
                                {
                                    Monitor.Pulse(WaitTillQueueEmptiesOrHalted);
                                }
                            }
                        }
                        if (_discardPendingRequests)
                        {
                            break; // jump out of the loop immediately
                        }
                        if (RequestQueue.Count != 0)
                        {
                            try
                            {
                                RequestToProcess = RequestQueue.Dequeue();
                                QueueIsFull = !IsQueueAvailableForEnqueue();
                                if (!QueueIsFull)
                                {
                                    lock (_waitForQueueToBeAvailableForEnqueue) Monitor.Pulse(_waitForQueueToBeAvailableForEnqueue);
                                }
                                processthisRequest = true;
                            }
                            catch (Exception error)
                            {
                                //log system error
                            }
                        }
                    }
                    catch (Exception errorOuter)
                    {
                        //log system error
                    }
                    finally
                    {
                        Monitor.Exit(_queueLocker);
                    }
                }
                else
                {
                    //waiting for more than 500MS for dequeuing could be an indication of some problem.
                    //Log system error
                }
                if (processthisRequest)
                {

                    lock (_processLocker)
                    {
                        //Wait for pulse, if some synched request is pending or processing.
                        while (_synchedRequestStatus == RequestStatus.Pending || _synchedRequestStatus == RequestStatus.InProcess)
                        {
                            Monitor.Wait(_processLocker, 3000); //recheck after every 3 seconds.
                        }
                        ProcessRequest(RequestToProcess, true);
                    }
                }
                if (_exitWhenQueueIsEmpty && RequestQueue.Count == 0)
                {
                    if (RequestQueue.Count == 0)
                    {
                        DoWhenQueueGetsEmpty();
                    }
                    break; // jump out of the loop if queue is empty.
                }
            }
            lock (WaitTillQueueEmptiesOrHalted)
            {
                Monitor.Pulse(WaitTillQueueEmptiesOrHalted);
            }
            _isQueueAlive = false;
            lock (WaitTillQueueCloses)
            {
                Monitor.Pulse(WaitTillQueueCloses); //Client systems can wait on this object so as to get signaled when queue exits
            }
        }

Following is the complete code of the class:

using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System;

namespace MyAwesomeCompany.Threading.Concurrent
{
    public enum RequestStatus { None, Pending, InProcess, Finished }
    public abstract class ConcurrentQueue<T>
    {
        #region declarations
        public readonly object WaitTillQueueCloses = new object();
        public readonly object WaitTillQueueGetsEmpty = new object();
        public readonly object WaitTillQueueEmptiesOrHalted = new object();
        Thread _processThread;
        bool _haltQueue = false;
        bool _closeQueue = false;
        bool _exitWhenQueueIsEmpty = false;
        bool _discardPendingRequests = false;
        private bool _isQueueAlive = false;
        private RequestStatus _synchedRequestStatus = RequestStatus.None;
        readonly object _queueLocker = new object();
        readonly object _waitForQueueToBeAvailableForEnqueue = new object();
        readonly object _processLocker = new object();
        internal bool QueueIsFull = false; //intially queue is not full
        protected Queue<T> RequestQueue = new Queue<T>();
        #endregion //declarations

        #region properties
        /// <summary>
        /// True if queue is halted.
        /// </summary>
        public bool IsQueueHalted { get { return _haltQueue; } }
        /// <summary>
        /// True indicates that the process thread is spinning - even if queue is halted.
        /// </summary>
        public virtual bool IsQueueAlive { get { return _isQueueAlive; } }
        /// <summary>
        /// True indicates queue is closed for further enqueing. IsQueuAlive may still be true because existing processes are going on.
        /// </summary>
        public bool IsQueueClosed { get { return _closeQueue; } }
        public int Count { get { return RequestQueue.Count; } }
        public bool IsQueueEmpty { get { return RequestQueue.Count == 0; } }
        #endregion //properties

        public ConcurrentQueue()
        {
        }

        #region public methods
        /// <summary>
        /// Discards all pending requests and deletes all requests in queue, queue is ready for new items to be enqued after this.
        /// </summary>
        public virtual void Reset()
        {
            lock (_queueLocker)
            {
                RequestQueue.Clear();
            }
        }
        /// <summary>
        /// Exits queue.
        /// </summary>
        /// <param name="discardPendingRequests"></param>
        public virtual void Exit(bool discardPendingRequests)
        {
            _exitWhenQueueIsEmpty = true;
            _discardPendingRequests = discardPendingRequests;
            _closeQueue = discardPendingRequests;
            lock (_queueLocker)
            {
                Monitor.Pulse(_queueLocker);
            }
        }
        /// <summary>
        /// Halts the queue process. 
        /// </summary>
        public virtual void HaltQueueProces()
        {
            _haltQueue = true;
        }
        /// <summary>
        /// Call if queue is halted and you want to restart it.
        /// </summary>
        public void ProceedQueueProcess()
        {
            lock (_queueLocker)
            {
                _haltQueue = false;
                Monitor.Pulse(_queueLocker);
            }
        }
        /// <summary>
        /// Processes the request.
        /// </summary>
        /// <param name="request">The request to process</param>
        /// <param name="Async">Is the request Async</param>
        /// <param name="isRecurssive">Is the request Recursive, meaning - was this method called from the Process itself. See example in notes.</param>
        /// <remarks>
        ///  Example 
        ///  Entity.Save 
        ///    `--~IsolatedStorageRequestQueue.Process~-----. 
        ///         `--~Entity(StopWatch).OnEntitySaved     |
        ///             `--~Entity(ActiveClockRecord).Save -'
        ///             
        /// </remarks>
        public void Process(T request, bool Async, bool isRecurssive)
        {
            if (_closeQueue) return;
            if (Async && (_processThread == null || !_processThread.IsAlive))
            {
                _processThread = new Thread(new ThreadStart(processQueue));
                _processThread.Name = "Process thread @ " + Environment.TickCount.ToString();
                _processThread.Start();
            }
            if (Async)
            {
                enqueueRequest(request);
            }
            else
            {
                if (!isRecurssive)
                {
                    _synchedRequestStatus = RequestStatus.Pending;
                    lock (_processLocker)
                    {
                        _synchedRequestStatus = RequestStatus.InProcess;
                        ProcessRequest(request, false);
                        _synchedRequestStatus = RequestStatus.Finished;
                        Monitor.Pulse(_processLocker);
                    }
                }
                else
                {
                    ProcessRequest(request, false);
                }
            }
        }
        /// <summary>
        /// This method executes as soon as the queue gets empty.[See remark for imp info]
        /// <remarks>
        ///  * It runs on the same thread which executes other requests in the queue.
        ///  * Currently there is no mechanism to abort this method.
        ///  * So, if a long running task is performed in this method, the new item in queue will only execute once this method finishes its task.
        /// </remarks>
        /// </summary>
        public virtual void DoWhenQueueGetsEmpty()
        {
            //to be implemented in derived class if required.
        }
        #endregion //public methods

        #region abstract members
        public abstract IEqualityComparer<T> QueueItemEualityComparer { get; }
        public abstract bool IsQueueAvailableForEnqueue();
        protected abstract void ProcessRequest(T Item, bool Async);
        #endregion

        #region private methods
        private void enqueueRequest(T request)
        {
            while (QueueIsFull)
            {
                lock (_waitForQueueToBeAvailableForEnqueue) Monitor.Wait(_waitForQueueToBeAvailableForEnqueue, 3000);
                QueueIsFull = !IsQueueAvailableForEnqueue();
            }
            lock (_queueLocker)
            {
                if (!RequestQueue.Contains(request, QueueItemEualityComparer))
                {
                    RequestQueue.Enqueue(request);
                    QueueIsFull = !IsQueueAvailableForEnqueue();
                }
                Monitor.Pulse(_queueLocker);
            }
        }
        private void processQueue()
        {
            _isQueueAlive = true;
            while (true)
            {
                T RequestToProcess = default(T);
                bool processthisRequest = false;
                if (RequestQueue.Count == 0)
                {
                    this.DoWhenQueueGetsEmpty();
                    lock (WaitTillQueueGetsEmpty)
                    {
                        Monitor.Pulse(WaitTillQueueGetsEmpty);
                    }
                    lock (WaitTillQueueEmptiesOrHalted)
                    {
                        Monitor.Pulse(WaitTillQueueEmptiesOrHalted);
                    }
                }
                if (Monitor.TryEnter(_queueLocker, 1000))
                {
                    try
                    {
                        while (_haltQueue || (RequestQueue.Count == 0 && !_exitWhenQueueIsEmpty && !_discardPendingRequests))
                        {
                            Monitor.Wait(_queueLocker, 7000);
                            if (_haltQueue)
                            {
                                lock (WaitTillQueueEmptiesOrHalted)
                                {
                                    Monitor.Pulse(WaitTillQueueEmptiesOrHalted);
                                }
                            }
                        }
                        if (_discardPendingRequests)
                        {
                            break; // jump out of the loop immediately
                        }
                        if (RequestQueue.Count != 0)
                        {
                            try
                            {
                                RequestToProcess = RequestQueue.Dequeue();
                                QueueIsFull = !IsQueueAvailableForEnqueue();
                                if (!QueueIsFull)
                                {
                                    lock (_waitForQueueToBeAvailableForEnqueue) Monitor.Pulse(_waitForQueueToBeAvailableForEnqueue);
                                }
                                processthisRequest = true;
                            }
                            catch (Exception error)
                            {
                                //log system error
                            }
                        }
                    }
                    catch (Exception errorOuter)
                    {
                        //log system error
                    }
                    finally
                    {
                        Monitor.Exit(_queueLocker);
                    }
                }
                else
                {
                    //waiting for more than 500MS for dequeuing could be an indication of some problem.
                    //Log system error
                }
                if (processthisRequest)
                {

                    lock (_processLocker)
                    {
                        //Wait for pulse, if some synched request is pending or processing.
                        while (_synchedRequestStatus == RequestStatus.Pending || _synchedRequestStatus == RequestStatus.InProcess)
                        {
                            Monitor.Wait(_processLocker, 3000); //recheck after every 3 seconds.
                        }
                        ProcessRequest(RequestToProcess, true);
                    }
                }
                if (_exitWhenQueueIsEmpty && RequestQueue.Count == 0)
                {
                    if (RequestQueue.Count == 0)
                    {
                        DoWhenQueueGetsEmpty();
                    }
                    break; // jump out of the loop if queue is empty.
                }
            }
            lock (WaitTillQueueEmptiesOrHalted)
            {
                Monitor.Pulse(WaitTillQueueEmptiesOrHalted);
            }
            _isQueueAlive = false;
            lock (WaitTillQueueCloses)
            {
                Monitor.Pulse(WaitTillQueueCloses); //Client systems can wait on this object so as to get signaled when queue exits
            }
        }
        #endregion
    }
}

In next posts we will create an example derived queue from ConcurrentQueue and use the queue in some example code to see the effect in foreground+background process.

Happy queue-ing!

Part 5