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.

 

Advertisements

ASO Tool: Cover Your Keywords

ASO Tool: Cover Your Keywords

Download KeywordsSearch.xlsx from GitHub.

ASO stands for App Store Optimization (like SEO; Search Engine Optimization). Know more here. To improve the chances of search engines or app stores (Windows Phone Store, Google Play, iTunes – Apple iPhone and iPAD Store) finding your app, your app needs a good description (apart from the keywords provided by the store) which includes as many related words. To achieve this, you would typically first decide your app related keywords and use them in app description. This is easier said than done. To help, I created this small tool in Microsoft Excel, which you can use to list down the keywords with value of importance, type description, and see the coverage of keywords you have used in your description. Download KeywordsSearch.xlsx from GitHub.

How to use?

ASO Excel Tool for Application Search Optimization Google Play Store Windows Phone

  1. Decide keywords and type them according to their value in the respective columns. High value keywords are those which are a must for app’s discoverability. Medium value keywords are important and low value ones are good to have.
  2. Type app’s description in this cell. Try to include as many keywords as possible in your text. As and when you want to see which of the keywords you have used in your description, either exit out of the cell by pressing Tab or press ctrl + Enter. You will notice that the words you have used in the text have now green background, and those which are still not used remain with red background. Keep typing and try to turn as many words as possible, green.
  3. The coverage section will show what percent of High, Medium, and Low value keywords you have used in the text you have typed.
  4. Legend section talks about meaning of color and formatting of text in keyword list.

C#|.NET Query String in Uri

C#|.NET Query String in Uri

In a not-so-basic-application you might have pages which are used for multiple similar purposes. You pass query string with many fields with multiple values between such pages (or web pages). In database driven apps, parameter values could be user generated and stored in the back-end and you pull more info from database on the basis of the value in query parameter. This is not the scenario of back-end driven app. This is more about “Field Names” and Values, which are part of the design and known to you while coding, and you want to manage them effectively and make the code more readable.

Let’s take an example:

You have a page in your app which loads different lists (ex: city, state, pin, salutation, etc.) and lets user select an item from the list. At different places in your app you pop this page up with required parameters to load appropriate items. The call to page looks something like this:

this.NavigationService.Navigate("/ListPicker.xaml?ListType=city",UriKind.Relative)

Let’s assume your page also has the ability for editing and you want to activate appropriate functionality (select only || edit). You would add one more parameter to your query, like so:

this.NavigationService.Navigate("/ListPicker.xaml?ListType=city&FormType=select",UriKind.Relative)

If you have many such pages, each have multiple fields and their multiple values, and you make calls to these pages from different places in your code, soon it will be very difficult to manage hard-coded query strings in Uri’s.

Here comes enum based solution:

We will have enums for fields and their values. For the purpose of this example we will keep single enum for fields and multiple enums for values for different fields. Let’s code
First define enums for fields and their values:

        internal enum QueryFields { ListPicker_FormType, ListPicker_ListType };
        internal enum ListTypes { City, States, Zip, Salutation };
        internal enum FormTypes { Select, Edit };

If you do not wish to be more detailed, you could simply build your Uri’s like so:

This.NavigationService.Navigate("/ListPicker.xaml?{0}={1}",QueryFields.ListPicker_FormType.ToString(), FormTypes.Select.ToString());
//The resultant uri - /ListPicer.xaml?ListPicker_FormType=Select

We will see below how you could parse query parameters in the called page and retrieve values in enum types.

Creating Uri as above still has string formatting which is not easy to maintain in multiple uses. To make things manageable and less error prone, let’s create a new enum for pages in the app and shift Uri building code in a single method which could be called from anywhere in the app with different field and values.

        internal enum AppPages {ListPicker, Setting, Main, etc };
        internal static Uri GetUri(AppPages appPage, params KeyValuePair<string, string>[] args)
        {
            string uriString = "";
            switch (appPage)
            {
                case AppPages.ListPicker:
                    uriString = "/Views/ListPicker.xaml";
                    break;
                case AppPages.Setting:
                    uriString = "/Views/Settings.xaml";
                    break;
                case AppPages.Main:
                    uriString = "/Main.xaml";
                    break;
                default:
                    uriString = "/Main.xaml";
                    break;
            }
            int counter = 0;
            string seperator = "?";
            foreach(KeyValuePair<string, string> query in args)
            {
                if (counter > 0) seperator = "&";
                uriString = String.Format("{0}{1}{2}={3}", uriString, seperator, query.Key, query.Value);
            }
            return new Uri(uriString, UriKind.Relative);
        }

With GetUri, you could create page navigation Uri with enums only instead of hard-coded strings:

            KeyValuePair<string, string> query_1 = new KeyValuePair<string,string>(QueryFields.ListPicker_FormType.ToString(), FormTypes.Select.ToString());
            KeyValuePair<string, string> query_2 = new KeyValuePair<string,string>(QueryFields.ListPicker_ListType.ToString(), ListTypes.City.ToString());
            This.NavigationService.Navigate(GetUri(AppPages.ListPicker, query_1, query_2));

Once you are navigated to your page, you need to parse query strings and extract enums which you could use in the page to decide page’s functionality.

At page level you need to have required enum type fields. For this example we will have two fields, one FormTypes type and other ListTypes type. A private processQuery method which accepts a dictionary sets these two fields appropriately.

        FormTypes formType;
        ListTypes listType;
        private void processQuery(Dictionary<string, string> query)
        {
            string _formTypeName = "";
            string _listTypeName = "";
            query.TryGetValue(QueryFields.ListPicker_FormType.ToString(), out _formTypeName);
            query.TryGetValue(QueryFields.ListPicker_ListType.ToString(), out _listTypeName);
            if (_formTypeName.Length != 0) formType = (FormTypes)(Convert.ToInt32(_formTypeName));
            if (_listTypeName.Length != 0) listType = (ListTypes)(Convert.ToInt32(_listTypeName));
        }

You would call processQuery method from OnNavigatedTo method of your page.

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            Dictionary<string, string> _params = new Dictionary<string, string>(NavigationContext.QueryString);
            processQuery(new Dictionary<string, string>());
        }

If you have 100’s of case statements (to choose a page) in GetUri, and you are concerned about performance, refactore the method to accept page name with path as string. With page path name directly in string, you would not need case statements. By the way, in my case with about 80+ cases to get PageName, the query creation does not take more than 50MS, which is negligible for me. More so, navigation calls are not recursive ones.

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
		}
	}

Transparent Live Tile For Windows Phone 8.1

Transparent Live Tile For Windows Phone 8.1

Windows Phone 8.1 Dev Preview

Windows Phone 8.1 developer preview is totally awesome. So what is one of the most important things app devs can do right away, without much fuss, to make their apps look great with Windows Phone 8.1? Revisit your app’s Live Tile images. Why? In 8.1, Start screen is mesmerizing with the parallax effect and Live Tile with background overlay. Dev preview users are going crazy with new Start experience, and I am sure, with public release, end users are going to love to have background image as well. Take a look at this awesome Nokia Lumia 925 Start screen:

wp_ss_20140416_0015[1]

When users have a background image, they might not like to have solid Live Tiles block their beautiful background. So, revisit your app’s Live Tile images – all of them! Check if they are transparent or not? If they are like Cortana, Avirall Time Suite, etc. in the image above, you are all set. You can safely ignore this article and find some other awesome way to improve your app for WP8.1 (think Cortana). If they are not, I suggest to update ‘em ASAP. And it’s easy, too. Let’s see how you can create transparent Live Tile images with Open Source Inkscape. You could choose to use Paint.NET (not MS Paint), Photoshop, GIMP, or any other tool which allows you to export image with transparency. Though I prefer GIMP for image editing but I chose Inkscape for this demo. Let’s go.

Step 1: Setup the page

InkScape01

  1. Open Inkscape and create a new document and Open Document Properties from file menu.
  2. In most cases app icons are solid white, if yours is one too, change the background color of the page, temporarily, to light yellow. This is while working only so that you can see white color. Before exporting we will reset this to transparent (this is very important).
  3. This example is for 336 X 336 medium tile. So set the custom size to 336 X 336.
  4. Make sure Units is “px”.

Step 2: Setup the drawing

InkScape02

Windows Phone 8 Asset Template Guide suggests a 336 X 336 tile to have 110px margin on all sides. Create 110px margin guides on all the sides. To create margin guides click and drag from the horizontal ruler on the top and from the vertical ruler on the left.

Step 3: Create Live Tile image of your app

InkScape03

The center part between the margins is the space where your tile image will go. Create your image here. For this example I simply dragged the box from tool box and made a hole in it 😀

Step 4: Set background to transparent

InkScape03a

To create a transparent Live Tile image we would like to have a transparent background. Go back in document properties and set Background to transparent by resetting “A” to 0. If your image is solid white, you might not see anything after making the background transparent. Don’t worry, your image is there (maybe somebody can tell how working space (not document background) in Inkscape can be made a different color than white).

Step 5: Export

InkScape04

  1. Open Export dialog from File > Export Bitmap…
  2. Set X0, X1, Y0, Y1 as shown in the image above.
  3. Browse for the image location, and make sure you give “PNG” as the extension of the image, NOT JPG or BMP.
  4. Export. (Alternatively, as suggested by Austin Andrews, you could export as SVG, and use his awesome service!)

Step 6: Check Final Image

WindowsPhotoViewer05

Notice that your final image does not have a white background. Windows Photo Viewers’s light blue background is your image’s background.

You are done. You would want to change all Live Tile images of your app in the same way. A transparent Live Tile image will encourage users to have your app pinned to Start screen without obstructing their beautiful background images.

Respect your users!

Download Lumia 925 Emulator Skin

Have you seen this feature demo video of Avirall? (jump to 00:50)

Do you like the emulator? This is Visual Studio Windows Phone Nokia Lumia 925 emulator skin, i created :D.

Nokia925_UP

You can also create your own app demo video with this skin! Download this skin from here.

Instructions about how to apply skin to your emulator are here.

Happy skinning, oops!

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.