Accelerate App Reviews

Accelerate App Reviews

Asking for review in your app? It’s tricky. If not done with due diligence, on encountering your request to review, users might get annoyed and still worse, they could rate your app low even though they liked it. A simplistic solution of asking for review after N days from installation (or first use) and N days after user has chosen “remind me later”, is not an appropriate solution. Why? User might have installed your app, ran it, exited, came back after N days and they were presented with a review request message, whereas, they had only used the app once. This is not a nice experience. Asking for review when user is exiting the app is less effective because user already has something else in their mind when they are coming out of the app.

Though there is no one solution that fits all, but this is how I try to tackle this scenario in my app. It’s not the “number of days” but “total minutes user has used your app” is my criteria to decide the interval of popping review message. I keep a record of overall usage of the app, and after a designated number of minutes, I pop a request to user. You might have to go through some trial and error to come up with the right “number of minutes” when you want to request. Determine whether your app is highly immersive or a quick open and shut type of app. In an immersive app|game you might want your review requests at longer intervals. In a less immersive app, you would rather ask earlier and at a less frequency. Then, you might want to gradually decrease the interval between requests during session. Don’t forget to code your logic in such a way that you could easily tune request intervals and accumulative usage time and update your app as soon as you realize that a change in the times is required. Here is pseudo-code for indication purpose:


[THIS IS PSEUDO CODE FOR INDICATION ONLY]

constant int POP_REQUEST_AFTER_ACCUMULATIVE_USAGE (adjusting knob) 
constant int POP_REQUEST_INTERVAL (adjusting knob : Initial interval between requests in the session) 
constant int POP_REQUEST_INTERVAL_DECREASE_BY (adjusting knob : Decrease interval after every request) 
constant int POP_REQUEST_INTERVAL_MINIMUM (adjusting knob : interval should not go below this)

int AccumulativeAppUsage (persist this info in storage)
DateTime LastReviewRequest;
Int ReviewRequestInterval = POP_REQUEST_INTERVAL;

App.Start | App.Activate
	DateTime AppStart
	LastReviewRequest = DateTime.Now //reset

App.Stop | App.Deactivate
	AccumulativeAppUsage += DateTime.NOW – AppStart
	Save AccumulativeAppUsage

Page.[identify the event which triggers PopRequest method]
	PopRequest()

PopRequest()
	totalUsageTillNow = AccumulativeAppUsage += DateTime.NOW – AppStart
	if(totalUsageTillNow >= POP_REQUEST_AFTER_ACCUMULATIVE_USAGE)
	{
		If(DateTime.Now – LastReviewRequest >= ReviewRequestInterval)
		{
			Show review request
			LastReviewRequest = DateTime.Now
			If(ReviewRequestInterval > POP_REQUEST_INTERVAL_MINIMUM)
				ReviewRequestInterval -= POP_REQUEST_INTERVAL_DECREASE_BY
		}
	}

UI | UX By & For Dev : User Focus

UI | UX By & For Dev : User Focus

As a developer, if I need to pick a concept which I find most important in deciding the placement of information, then it is the user focus areas on screen. You want your users to find more important information swiftly so you keep those elements in the areas of the screen which get more focus and keep less important elements in areas which are less intrusive during user scanning the page. Have a look at following imaginary compartmentalization of screen areas:

Sufrace Pro 3 Screen Elements Placement UX UI

Green dots represent user focus. So, 1,2 and 5 are the areas which are going to get most focus of user. Then come 3, 6, and 9. And the least focus grabbing areas are 4, 7 and 8. The arrows show the shifting of user gaze while they are scanning your app’s page. This shifting of gaze is closely related to the focus areas. User’s focus shifts in this sequence (not very strictly but generally)
1 > 2 > 5 > 3 > 6 > 9 > 4 > 8 > 7.

This can be a great guide to plan control/element placement in your app.

Microsoft Visual Layout Guide

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.

C# Extension: Random Pastel Colors

C# Extension: Random Pastel Colors

In last post we wrote extension method to get complementary color of a given color. In this post we will write some more extension methods to get colors. Co-incidentally India is totally covered in colors because this is the Holi week.
If you want to have a dynamic feel to your app (or some part of your app) you could fill it with random colors. Let’s write following extension methods which return random color with parameterized control over what type of color output you need:

  • Color.GetRandom – This method returns a random color.
  • Color.GetRandom(Brightness Control) – This method returns a random color between given brightness.
  • Color.GetRandomShade – This returns a random color of the Color’s shade.
  • Color.GetRandomShade(Brightness Control) – It returns a random color of given color between given brightness.
  • Color.GetPastelShade() – Returns a pastel shade of given color.

Let’s code.
We will utilize the same code from our last post and extend the ColorExtensions class. To implement aforesaid methods, add following code to the said class

        static Random randomizer = new Random();
        /// <summary>
        /// Returns a pastel shade of the color
        /// </summary>
        /// <param name="source">Source  color</param>
        /// <returns></returns>
        public static Color GetPastelShade(this Color source)
        {
            return (generateColor(source, true, new HSB { H = 0, S = 0.2d, B = 255 }, new HSB { H = 360, S = 0.5d, B = 255 }));
        }
        /// <summary>
        /// Returns a random color
        /// </summary>
        /// <param name="source">Ignored(Use RandomShade to get a shade of given color)</param>
        /// <returns></returns>
        public static Color GetRandom(this Color source)
        {
            return (generateColor(source, false, new HSB { H = 0, S = 0, B = 0 }, new HSB { H = 360, S = 1, B = 255 }));
        }
        /// <summary>
        /// Returns a random color within a brightness boundry
        /// </summary>
        /// <param name="source">Ignored (Use GetRandomShade to get a random shade of the color)</param>
        /// <param name="minBrightness">A valued from 0.0 to 1.0, 0 is darkest and 1 is lightest</param>
        /// <param name="minBrightness">A valued from 0.0 to 1.0</param>
        /// <returns></returns>
        public static Color GetRandom(this Color source, double minBrightness, double maxBrightness)
        {
            if (minBrightness >= 0 && maxBrightness <= 1)
            {
                return (generateColor(source, false, new HSB { H = 0, S = 1 * minBrightness, B = 255 }, new HSB { H = 360, S = 1 * maxBrightness, B = 255 }));
            }
            else
            {
                throw new ArgumentOutOfRangeException();
            }
        }
        /// <summary>
        /// Returns a random shade of the color
        /// </summary>
        /// <param name="source">Base color for the returned shade</param>
        /// <returns></returns>
        public static Color GetRandomShade(this Color source)
        {
            return (generateColor(source, true, new HSB { H = 0, S = 1, B = 0 }, new HSB { H = 360, S = 1, B = 255 }));
        }
        /// <summary>
        /// Returns a random color within a brightness boundry
        /// </summary>
        /// <param name="source">Base color for the returned shade</param>
        /// <param name="minBrightness">A valued from 0.0 to 1.0, 0 is brightest and 1 is lightest</param>
        /// <param name="minBrightness">A valued from 0.0 to 1.0</param>
        /// <returns></returns>
        public static Color GetRandomShade(this Color source, double minBrightness, double maxBrightness)
        {
            if (minBrightness >= 0 && maxBrightness <= 1)
            {
            return (generateColor(source, true, new HSB { H = 0, S = 1 * minBrightness, B = 255 }, new HSB { H = 360, S = 1 * maxBrightness, B = 255 }));
            }
            else
            {
                throw new ArgumentOutOfRangeException();
            }
        }
        /// <summary>
        /// Process parameters and returns a color
        /// </summary>
        /// <param name="source">Color source</param>
        /// <param name="isaShadeOfSource">Should source be used to generate the new color</param>
        /// <param name="min">Minimum range for HSB</param>
        /// <param name="max">Maximum range for HSB</param>
        /// <returns></returns>
        private static Color generateColor(Color source, bool isaShadeOfSource, HSB min, HSB max)
        {
            HSB hsbValues = ConvertToHSB(new RGB { R = source.R, G = source.G, B = source.B });
            double h_double = randomizer.NextDouble();
            double s_double = randomizer.NextDouble();
            double b_double = randomizer.NextDouble();
            if (max.B - min.B == 0) b_double = 0; //do not change Brightness
            if(isaShadeOfSource)
            {
                min.H = hsbValues.H;
                max.H = hsbValues.H;
                h_double = 0;
            }
            hsbValues = new HSB
            {
                H = Convert.ToDouble(randomizer.Next(Convert.ToInt32(min.H), Convert.ToInt32(max.H))) + h_double,
                S = Convert.ToDouble((randomizer.Next(Convert.ToInt32(min.S * 100), Convert.ToInt32(max.S * 100)))/100d),
                B = Convert.ToDouble(randomizer.Next(Convert.ToInt32(min.B), Convert.ToInt32(max.B))) + b_double
            };
            Debug.WriteLine("H:{0} | S:{1} | B:{2} [Min_S:{3} | Max_S{4}]", hsbValues.H,_hsbValues.S,_hsbValues.B, min.S, max.S) ;
            RGB rgbvalues = ConvertToRGB(_hsbValues);
            return new Color { A = source.A, R = (byte)_rgbvalues.R, G = (byte)_rgbvalues.G, B = (byte)_rgbvalues.B };
        }

You could call these methods like so:

Color randomPurplishPastel = Colors.Purple.GetPastelShade();

Here is an example :

My app uses random colors pretty extensively:

Avirall Time Suite | Nokia Lumia 1520

Holi hai!!!

C# Extension: Complementary Color

C# Extension: Complementary Color

In the image above blue & orange are complementary colors, green and red are complementary colors, purple and yellow are complementary colors, etc. The formula is; two colors, placed exactly opposite to each other on color wheel are complementary. You use complementary color combination to highlight a particular item in your design. For example, if most part of your screen has blue color, for important elements on the screen you would choose orange color. Photographers and painters know about importance of complementary color in making their paintings and photographs beautiful:

Complementary Colors by OneEighteen, on Flickr
Complementary Colors, a photo by OneEighteen on Flickr.

In case your app design is dynamic which gives control to the user to choose a dominant color in your app, e.g. background color, you would want to know the contrast color of the chosen color on-the-fly. Particularly in Windows Phone apps, if you incorporate user selected accent color in app design, for some important elements you might need contrast color. For example, in following screenshot of my app, the accent color on the phone is magenta and the color of the hands, auto generated in code, is green.

QSQIn1020Small

This extension method of Color class returns the contrast color:
(HSB and RGB conversion code courtesy, Yi-Lun Luo)

namespace MyCompany.AwesomeExtensions.MediaHelpers
{
    public static class ColorExtensions
    {
        static Random randomizer = new Random();
        public static Color GetContrast(this Color source, bool preserveOpacity)
        {
            Color inputColor = source;
            //if RGB values are close to each other by a diff less than 10%, then if RGB values are lighter side, decrease the blue by 50% (eventually it will increase in conversion below), if RBB values are on darker side, decrease yellow by about 50% (it will increase in conversion)
            byte avgColorValue = (byte)((source.R + source.G + source.B) / 3);
            int diff_r = Math.Abs(source.R - avgColorValue);
            int diff_g = Math.Abs(source.G - avgColorValue);
            int diff_b = Math.Abs(source.B - avgColorValue);
            if (diff_r < 20 && diff_g < 20 && diff_b < 20) //The color is a shade of gray
            {
                if (avgColorValue < 123) //color is dark
                {
                    inputColor.B = 220;
                    inputColor.G = 230;
                    inputColor.R = 50;
                }
                else
                {
                    inputColor.R = 255;
                    inputColor.G = 255;
                    inputColor.B = 50;
                }
            }
            byte sourceAlphaValue = source.A;
            if (!preserveOpacity)
            {
                sourceAlphaValue = Math.Max(source.A, (byte)127); //We don't want contrast color to be more than 50% transparent ever.
            }
            RGB rgb = new RGB { R = inputColor.R, G = inputColor.G, B = inputColor.B };
            HSB hsb = ConvertToHSB(_rgb);
            hsb.H = hsb.H < 180 ! hsb.H + 180 : hsb.H - 180;
            //hsb.B = isColorDark ? 240 : 50; //Added to create dark on light, and light on dark
            rgb = ConvertToRGB(_hsb);
            return new Color { A = sourceAlphaValue, R = rgb.R, G = (byte)rgb.G, B = (byte)rgb.B };
        }
        internal static RGB ConvertToRGB(HSB hsb)
        {
            // By: <a href="http://blogs.msdn.com/b/codefx/archive/2012/02/09/create-a-color-picker-for-windows-phone.aspx" title="MSDN" target="_blank">Yi-Lun Luo</a>
            double chroma = hsb.S * hsb.B;
            double hue2 = hsb.H / 60;
            double x = chroma * (1 - Math.Abs(hue2 % 2 - 1));
            double r1 = 0d;
            double g1 = 0d;
            double b1 = 0d;
            if (hue2 >= 0 && hue2 < 1)
            {
                r1 = chroma;
                g1 = x;
            }
            else if (hue2 >= 1 && hue2 < 2)
            {
                r1 = x;
                g1 = chroma;
            }
            else if (hue2 >= 2 && hue2 < 3)
            {
                g1 = chroma;
                b1 = x;
            }
            else if (hue2 >= 3 && hue2 < 4)
            {
                g1 = x;
                b1 = chroma;
            }
            else if (hue2 >= 4 && hue2 < 5)
            {
                r1 = x;
                b1 = chroma;
            }
            else if (hue2 >= 5 && hue2 <= 6)
            {
                r1 = chroma;
                b1 = x;
            }
            double m = hsb.B - chroma;
            return new RGB()
            {
                R = r1 + m,
                G = g1 + m,
                B = b1 + m
            };
        }
        internal static HSB ConvertToHSB(RGB rgb)
        {
           // By: <a href="http://blogs.msdn.com/b/codefx/archive/2012/02/09/create-a-color-picker-for-windows-phone.aspx" title="MSDN" target="_blank">Yi-Lun Luo</a>
            double r = rgb.R;
            double g = rgb.G;
            double b = rgb.B;

            double max = Max(r, g, b);
            double min = Min(r, g, b);
            double chroma = max - min;
            double hue2 = 0d;
            if (chroma != 0)
            {
                if (max == r)
                {
                    hue2 = (g - b) / chroma;
                }
                else if (max == g)
                {
                    hue2 = (b - r) / chroma + 2;
                }
                else
                {
                    hue2 = (r - g) / chroma + 4;
                }
            }
            double hue = hue2 * 60;
            if (hue < 0)
            {
                hue += 360;
            }
            double brightness = max;
            double saturation = 0;
            if (chroma != 0)
            {
                saturation = chroma / brightness;
            }
            return new HSB()
            {
                H = hue,
                S = saturation,
                B = brightness
            };
        }
        private static double Max(double d1, double d2, double d3)
        {
            if (d1 > d2)
            {
                return Math.Max(d1, d3);
            }
            return Math.Max(d2, d3);
        }
        private static double Min(double d1, double d2, double d3)
        {
            if (d1 < d2)
            {
                return Math.Min(d1, d3);
            }
            return Math.Min(d2, d3);
        }
        internal struct RGB
        {
            internal double R;
            internal double G;
            internal double B;
        }
        internal struct HSB
        {
            internal double H;
            internal double S;
            internal double B;
        }
    }
}

Get working code from my GitHub repository (POCs).

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#|.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

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

Queue by oatsy40, on Flickr
Queue, a photo by oatsy40 on Flickr.

Visit these posts for Part 1 & Part 2

I wrote ConcurrentQueue as Generic Abstract class in c# with limited .NET. You can see the complete mechanism at play in my app. The class provides an easy enqueue of process requests on background thread. The client does not have to bother much about the threading etc., they can just call a method to enqueue requests which they want to process in the background. With FIFO method queue does its work in the background. The derived classes of ConcurrentQueue decide two most important aspects of the queue – type of the request and the related process of the request. Type of request is taken care of by Generics and process related to request is to be implemented by the derived class. Process and request could have been implemented with Task & Delegate but I was more comfortable with straight forward methods. In some future version I might update it and implement it with Task.

Let’s take a look at the class diagram:

ClassDiagram

RequestStatus enum is currently used internally to register the status of a request in the queue. I will not discuss fields, we will know about them when we go through the code. Let’s have a look at the properties and methods:

Properties

  • Count: Returns the number of requests waiting in the queue.
  • IsQueueAlive: Returns Boolean to indicate whether is queue is alive to take/process requests.
  • IsQueueClosed: Returns Boolean to indicate if queue is available for new request or not.
  • IsQueueEmpty: Reurns Boolean to inform whether queue has requests or not.
  • IsQueueHalted: Returns Boolean. True indicates queue is not processing any request and waiting to be started again.
  • QueueItemEqualityComparer: The derived class determines equality comparer for the type.

Methods

  • ConcurrentQueue : Constructor
  • DoWhenQueueGetsEmpty: Executes on the process thread when queue gets empty. This is a virtual method for derived class to add more functionality.
  • Exit: Client calls this method to signal an exit with appropriate exiting behavior. Queue is not guaranteed to exit immediately. Derived class can extend the logic of this virtual method for exiting queue process.
  • HaltQueueProcess: Client calls this method to halt background process of the queue. Background process completes the current process and waits for signal (from ProceedQueueProcess) to take up next request in queue. During queue is in halt state, new requests can still be enqueued. This is a virtual method and derived class can extend it.
  • ProceedQueueProcess: Client calls this method to bring the queue out of the halt.
  • IsQueueAvailableForEnqueu: Derived class implements logic in this abstract method to determine whether queue should be considered as available for enqueue.
  • Process: Client calls this method to enqueue request.
  • ProcessRequest: The background thread calls this abstract method for processing. Each derived class implements the process for the request.
  • Reset: Queue is emptied and made ready for a new enqueue.

Next, we will go through the internal code of the class.

Part 4