C#: Most Recently Used List


I wanted to add a button to one of the applications that I wrote that listed the last ten reports that a user has viewed so they could quickly and easily access recently viewed reports. I found a lot of information about how to create a Most Recently Used (MRU) list of files that have been opened but I couldn’t find anything built into the .NET Framework to create a custom list of objects where the most recently used item was at the beginning of the list.

I’m sure many of you are saying to yourself, “Why didn’t he just use a stack?”. The reason I didn’t use the already built Stack class is because I needed to implement two other features:

  • Restrict the size of the set
  • Ensure no duplicate items exist in the set

The Stack class found in the System.Collections namespace doesn’t enforce these two properties inherently and thus the need for a custom collection.

Note: I could have optimized this collection a bit more by adding each item to the end of the list and keeping a pointer to the location of the true first item but given the fact that I only will be storing a few items in the set, I didn’t take the time to implement it that way. I leave that optimization to you.

/// <summary>
/// Stores a set of items with the most recently added at item the front and the 
/// least recently added item at the end
/// </summary>
public class RecentSet<T> : IEnumerable<T>
{
    private List<T> _list;
    private int _size = -1;

    /// <summary>
    /// Creates a new RecentSet object.
    /// </summary>
    public RecentSet()
    {
        _list = new List<T>();            
    }
     /// <summary>
    /// Creates a new RecentSet object with a fixed size. The return set may be smaller than
    /// the specified size but it will never be larger
    /// </summary>
    /// <param name="size">The maximum size of the set</param>
    public RecentSet(int size)
    {
        _list = new List<T>();
        _size = size;
    }
 
    /// <summary>
    /// Creates a new RecentSet object initializing it with the indicated items. Note: 
    /// the initialized RecentSet will be in the order of parameter items.  If items are {1, 2, 3, 4},
    /// iterating through RecentSet will result in a list of {1, 2, 3, 4} not {4, 3, 2, 1}        
    /// </summary>
    public RecentSet(IEnumerable<T> items)
    {
        _list = items.ToList();
    }

    /// <summary>
    /// Creates a new RecentSet object with a fixed size initializing it with the indicated items. Note: 
    /// the initialized RecentSet will be in the order of parameter items.  If items are {1, 2, 3, 4},
    /// iterating through RecentSet will result in a list of {1, 2, 3, 4} not {4, 3, 2, 1}        
    /// </summary>
    public RecentSet(int size, IEnumerable<T> items)
    {
        _list = items.ToList();
        _size = size;

        TrimList();
    }

    /// <summary>
    /// Adds an item to the RecentSet
    /// </summary>
    public void Add(T item)
    {
        // If the item is already in the set, remove it
        int i = _list.IndexOf(item);
        if (i > -1)
            _list.RemoveAt(i);

        // Add the item to the front of the list.
        _list.Insert(0, item);

        TrimList();
    }

    public int Count
    {
        get { return _list.Count; }
    }

    private void TrimList()
    {
        // If there is a set size, make sure the set only contains that many elements
        if (_size != -1)
            while (_list.Count > _size)
                _list.RemoveAt(_list.Count - 1);
    }

    /// <summary>
    /// Returns the set in the form of a List
    /// </summary>
    public List<T> ToList()
    {
        return _list;
    }

    #region IEnumerable<T> Members

     public IEnumerator<T> GetEnumerator()
    {           
        return _list.GetEnumerator();
    }

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return _list.GetEnumerator();
    }

    #endregion
}

C#: MD5 Hash Method


I needed to create an MD5 hash of a string today that could be sent along with a web service request to a third party application. I’ve never done this before using .NET but it was exteremely simple! Here is the code:

/// <summary>
/// Gets the MD5 hash value for the passed in value parameter
/// </summary>
/// <param name="value">The string value to hash</param>
/// <param name="upperCase">Indicates whether or not the return value should be upper case</param>
/// <returns>The MD5 hash of the value parameter</returns>
public static string GetMD5Hash(string value, bool upperCase)
{
    // Instantiate new MD5 Service Provider to perform the hash
    System.Security.Cryptography.MD5CryptoServiceProvider md5ServiceProdivder = new System.Security.Cryptography.MD5CryptoServiceProvider();
            
     // Get a byte array representing the value to be hashed and hash it
    byte[] data = System.Text.Encoding.ASCII.GetBytes(value);
    data = md5ServiceProdivder.ComputeHash(data);

    // Get the hashed string value
    StringBuilder hashedValue = new StringBuilder();
    for (int i = 0; i < data.Length; i++)
        hashedValue.Append(data[i].ToString("x2"));

    // Return the string in all caps if desired
    if (upperCase)
        return hashedValue.ToString().ToUpper();

    return hashedValue.ToString();
}

C#: Word Mail Merge Bypass Header Record Delimiters Popup


One of the applications that I have written allows the user to create custom form letters in Microsoft Word. The user is able to create a Word document and populate it with mail merge fields and then I programmatically create the mail merge data source and perform the merge. Everything worked fantastic except when the user created a form letter that only contained one merge field. Under this circumstance, every time they attempted to perform the merge from within my application, Microsoft Word would pop up with the Header Record Delimiters window, shown below, asking the user to specify how the fields and the records were delimited.

With more than one field, Microsoft Word was able to automatically detect the tab that was inserted between fields and use it as the delimiter but with only one field, it could not. The solution to this problem is actually so simple that I felt a bit retarded that I didn’t think of it earlier. All you have to do is add another merge field in your data file so that there is never only one merge field! The second column of data in your merge file will not correspond to any merge field in the document but Word doesn’t complain about it and it is able to automatically detect the tab between fields.

So, if you only have one merge field, just setup your data file to look something like the following:

MergeField1 [DUMMY_FIELD]
Data1 NULL
Data2 NULL
Data3 NULL

Note: You obviously can put whatever you want for the data in the DUMMY_FIELD column. I just put the string NULL for kicks.

LINQ: Flatten a List of Lists


Today I needed to flatten a list of lists and really didn’t want write out a nested loop to iterate through each element in each list. After some searching I found that LINQ provides a very elegant solution to this problem. LINQ is a powerful set of extensions that were added to the .NET Framework that allows you to query and manipulate sets of data. The SelectMany extension method solves this problem very easily as shown below.

List<List<string>> listOfLists = new List<List<string>>();
listOfLists.Add(new List<string>() { "a", "b", "c" });
listOfLists.Add(new List<string>() { "d", "e", "f" });
listOfLists.Add(new List<string>() { "g", "h", "i" });

var flattenedList = listOfLists.SelectMany(x => x);

foreach (string s in flattenedList)
     Console.Write(s + " ");

// Output
// -----
// a b c d e f g h i

Justin Etheridge has a great blog post with awesome diagrams of how the SelectMany extension method works. Check it out for more information.

Posted in LINQ. Tags: , . 3 Comments »

ASP.NET AJAX ModalPopup to Confirm Delete


As mentioned in my last post I have been working with the ASP.NET AJAX Toolkit lately and more specifically the ModalPopupExtender control. On one of the pages I have a DataGridView with a delete ImageButton and I wanted to use the ModalPopup control to confirm that the user really wanted to delete the row from the DataGridView. This question has been asked many times on many different forums but the most common response seems to be, “That is completely overkill. Just use the confirm() javascript method”. While this may be a true statement, the confirm() method has some drawbacks one of which is that you can’t customize the window to the look and feel of your website.

Confirming an action is a very common scenario, one that will occur on many pages and even multiple times on one page. Such a situation obviously calls for a custom control and that is exactly what I did. After creating the custom control, which will be explained shortly, adding a confirmation box is accomplished by inserting the following markup into your page:

<enso:ConfirmBox runat="server" 
     Title="Confirm Delete" 
     Message="Are you sure you want to delete this product key?" 
     TargetControlId="btnDeleteProductKey"  />

This one simple line will create a confirmation box that can be completely customized to fit the look and feel of your site as shown below.

Now for the explanation.

To create a new user control:

  1. In the Solution Explorer of Visual Studio right click the project name, select Add, and click New Item…
  2. Select Web User Control
  3. Enter ConfirmBox.ascx in the Name textbox
  4. Copy and paste the following code into the ConfirmBox.ascx window.
<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ConfirmBox.ascx.cs" Inherits="TestWebApp.ConfirmBox" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="asp" %>

<script runat="server">
    public string Title { set { this.lblTitle.Text = value; } }
    public string Message { set { this.lblMessage.Text = value; } }
    public string TargetControlId { set { this.popupConfirmBox.TargetControlID = this.btnConfirm.TargetControlID = value; } }
    public int Width { set { this.panelConfirmBox.Width = Unit.Pixel(value); } }

    protected void Page_Load(object sender, EventArgs e)
    {
        this.btnPopupClose.OnClientClick = "$find('" + popupConfirmBox.ClientID + "').hide();";
    }
</script>
  
<asp:Panel ID="panelConfirmBox" runat="server" CssClass="modalPopup" Width="400px" Style="display:none;">
    <h5><asp:Label ID="lblTitle" runat="server" Text="[Title]"></asp:Label></h5>
    <div class="closeButton">
        <asp:LinkButton ID="btnPopupClose" runat="server" >x</asp:LinkButton>
    </div>    
    <div class="clearBoth"></div>
    
    <br />  
    <div class="modalMessage">
        <asp:Label ID="lblMessage" runat="server" Text="[Message]"></asp:Label>
    </div>
    <br />
    
    <div class="modalButtons">
        <asp:Button ID="btnYes" runat="server" Text="Yes" /> &nbsp; <asp:Button ID="btnNo" runat="server" Text="No" />
    </div>
</asp:Panel>                    
<asp:ModalPopupExtender Id="popupConfirmBox" runat="server" PopupControlID="panelConfirmBox" BackgroundCssClass="modalBackground" CancelControlID="btnNo" OkControlId="btnYes" ></asp:ModalPopupExtender>
<asp:ConfirmButtonExtender ID="btnConfirm" runat="server" DisplayModalPopupID="popupConfirmBox"> </asp:ConfirmButtonExtender>

You will need to change the Inherits property in the first line of the file to match the name of your application. Additionally, you will need to make sure you already have a reference to the AjaxControlToolkit.dll in your project.

Property Definitions:

  • Title – Sets the title of the confirmation box
  • Message – Sets the message of the confirmation box
  • TargetControlId – Sets the id of the control that should display the confirmation box when clicked
  • Width – Sets the width confirmation box

The only non-appearance property is the TargetControlId which as in all ASP.NET AJAX Toolkit controls is the id of the control that is to be extended. In our case, setting this property will set the TargetControlId property of both the ModalPopupExtender and the ConfirmButtonExtender. For these to work in conjunction, they must both have the same value for the TargetControlId property.

If you read my previous post, ASP.NET AJAX Toolkit ModalPopup Tips, I mentioned a few tricks I learned while using the ModalPopupExtender; one of which was how to add multiple cancel buttons. This can be accomplished with a bit of client-side javascript placed in the OnClientClick event of a LinkButton. In the Page_Load event of the control we are adding this javascript to the ‘x’ in the top right corner of the window. Note that we are accessing the ClientID property of the ModualPopupExtender as when the page is rendered, the control will no longer have an Id of ‘popupConfirmationBox’ but rather something like ”ctl00_contentMain_dataGridViewProductKeys_ctl02_ctl01_popupConfirmBox’.

There is nothing fancy to the configuration of the ModalPopupExtender. We simply set the panel that will appear when the TargetControlId is clicked and the cancel and ok control ids.

Next we introduce another ASP.NET AJAX Toolkit control called the ConfirmButtonExtender. As the name indicates, it is used to confirm an action taken by the user. The plain vanilla version of this control simply uses the javascript function confirm() as discussed earlier in this post. But, the developers were nice enough to allow us to specify a ModalPopup control to be displayed instead. We simply set the DisplayModalPopupID property to the Id of our ModalPopupExtender to let the control know to display the ModalPopup instead.

Before we can start using this control on any page we desire, we need to make a simple modification to the web.config to ensure the control is visible throughout the site. Open your web.config and find the pages section which is a child of the system.web node. Add something similar to the last line that appears in the controls section below. Note that the tagPrefix and tagName can be anything you desire but just make them something you can remember as they will be used to identify your control.

<system.web>
    <pages>
      <controls>
        <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        <add tagPrefix="enso" src="~/ConfirmBox.ascx" tagName="ConfirmBox"  />
      </controls>
    </pages>
</system.web>

Save the web.config file and build your project to make the control visible while using intellisense. Now navigate to the page on which you want to place the ConfirmBox control. In my case I wanted to add it to a DataGridView delete button. To do this I added a TemplateField to the DataGridView using the following markup.

<asp:TemplateField ShowHeader="false">
     <ItemTemplate>
          <asp:ImageButton ID="btnDeleteProductKey" runat="server" CommandName="Delete" ImageUrl="~/Styles/images/X.png" />
          <enso:ConfirmBox runat="server" Title="Confirm Delete" Message="Are you sure you want to delete this product key?" TargetControlId="btnDeleteProductKey"  />
     </ItemTemplate>
</asp:TemplateField>

Lastly you will need to make sure you have a ScriptManager on the page somewhere and a link to the stylesheet used to format your confirmation box. Click here for the stylesheet and here for the image used in my implementation.

Simply add the markup for the new control you created, specify the Title, Message, and TargetControlId and you are done! You have now implemented a confirmation box that you can placee anywhere on any page without having to duplicate code over and over!

ASP.NET AJAX Toolkit ModalPopup Tips


Today I was working with the ModalPopup control provided by Microsoft in the ASP.NET AJAX Toolkit. This control allows you to create a popup box that removes the users ability to interact with the underlying page until the box is closed. Below is a screenshot from my implementation which was used in a customer managment web application used to create product keys.

Joe Stagner provides a great introductory video tutorial on this control here which got me off to a great start but I soon ran into my first problem.

If you setup the control exactly as described in the video and run your application in IE8, the background opacity is completely ignored and the entire window changes to an opaque gray. Unfortunately, IE8 does not support the opacity css property even though all other browsers do. After many complaints, Microsoft provided a work around that allows you to set the opacity of the page using a proprietary property named ‘-ms-filter’. In order to get the correct opacity in all browsers (IE8, 7, 6, Chrome, FireFox, etc), your CSS class must be in the following order:

.modalBackground
{        
    background-color: Gray;    
    -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";   /* IE 8 Compatibility */
    filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50);       /* IE 7 Compatibility */
    opacity: 0.5;    /* Everyone else */
}

My second issue was that when you click the OK button in the ModalPopup the control is designed to execute a javascript function but I needed to execute a server-side function in the code-behind file. To fix this, all you need to do is simply remove the OKControlID property from the ModalPopupExtender control. After doing this, the code-behind click event will be executed when the user clicks the OK button.

<asp:ModalPopupExtender 
     BehaviorID="popupAddProductKeys" 
     runat="server" 
     TargetControlID="btnAddProductKeys" 
     PopupControlID="panelAddProductKeys" 
     BackgroundCssClass="modalBackground"
     CancelControlID="btnProductKeysCancel">

Unfortunately, fixing this second issue caused another. In all non-IE browsers, clicking the OK button would not close the popup window. To fix this, two things need be done. First, set the BehaviorID property in the ModalPopupExtender control. Second, in the Button control, include the following javascript in the OnClientClick event.

<asp:Button 
     ID="btnProductKeysOk" 
     runat="server" 
     Text="OK" 
     OnClientClick="$find('popupAddProductKeys').hide()" 
     onclick="btnProductKeysOk_Click" />

The included javascript will find the ModalPopup control and then call its hide function and thus hide it from view. This trick can be used to add multiple close buttons on the popup. For instance, I added a LinkButton with the text of ‘x’ in the to right corner to allow the user another way to close the popup. To close the popup when clicked, simply place the same javascript as shown above in the OnClientClick event.

<asp:LinkButton 
     ID="btnPopupClose" 
     runat="server" 
     OnClientClick="$find('popupAddProductKeys').hide()">x</asp:LinkButton>

Arbitrary Sort


Sorting is an issue that traces way back to the beginning of programming. All programming languages provide different ways to sort different items. Many even allow you to implement your own comparison function so you can sort a list of items in any way you want; by length or string, in reverse order, string with the most spaces, etc. But, I ran into a sorting problem that couldn’t easily be solved by any built in functions. My problem is as follows: the application I’m writing allows the user to post transactions to a resident in an apartment and each transaction is associated with a category. Categories include Rent, Pet Fees, Late Fees, Storage Unit Charge, Garage Charge, Carport Charge, etc. When the user posts a payment, the payment needs to be applied to the various oustanding charges for the resident in an order that can be arbitrarily set by an administrator. For instance, if a user has an outstanding rent charge, late fee charge, and garage charge, an administrator could setup the application so that the payment would first be applied to the late fee, then the garage charge, and lastly the rent charge. So, when a payment is made, the outstanding charges need to be retrieved, and then ordered according to what the user has defined. There in lies the problem. I wasn’t trying to sort a list by length, alphabetically, or something simple like that, I needed to sort the list by the ordering in another list defined by the user.

To solve my problem, I built an anonymous typed class called ArbitrarySort that implements the IComparer interface. The constructor takes a List of objects of type T which defines the desired sort order. From the passed in List, a Dictionary with key of type T and value of type int is created. Each item in the List is added in order into the Dictionary with an associated value that is incremented by one after each addition. Thus, if you passed in the List

Dog
Cat
Mouse
Hampster

the corresponding Dictionary in (Key, Value) form would be:

(Dog, 1)
(Cat, 2)
(Mouse, 3)
(Hampster, 4)

The Compare method takes two arguments of type T and looks up the value associated with each item in the Dictionary and compares them. Thus, if the Compare method was called on “Hampster” and “Cat”, the method would compare the values 4 and 2 and 1 would be returned as “Hampster” is considered to be greater than “Cat” and comes later in the list.

With this class, I can pass in a list of all transaction categories ordered according to which category a payment should be applied first and then when a payment is received, a list of outstanding charges is sorted according to the predefined order in the ArbitrarySort class.

    /// <summary>
    /// Creates a sorting class that lets you sort a list of items in an arbitrary order.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class ArbitrarySort<T> : IComparer<T>
    {
        /// <summary>
        /// Dictionary that stores the objects used for ordering.  The key represents the
        /// object that is to be stored and the value is the index in the list.  Retrieving
        /// the value of an object will give the index it appears in the list.
        /// </summary>
        Dictionary<T, int> _sortOrder;

        /// <summary>
        /// Constructs a new ArbitrarySort class to sort a list in an abritrary order.
        /// </summary>
        /// <param name="sortOrder">Specifies the order in which items should be ordered.
        /// Example: To sort a list of single digit integers first by even numbers and then odd numbers, pass in { 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 }.</param>
        public ArbitrarySort(List<T> sortOrder)
        {
            // Create the dictionary
            _sortOrder = new Dictionary<T, int>();

            for (int i = 0; i < sortOrder.Count(); i++)
                _sortOrder.Add(sortOrder[i], i);
        }

        /// <summary>
        /// Compares two objects and returns a value indicating whether one is less than, equal to or greater than the other.
        /// </summary>
        /// <param name="x">First object of type T to compare.</param>
        /// <param name="y">Second object of type T to compare</param>
        /// <returns>If x is less than y then -1.  If x is equal to y then 0.  If x is greater than y then 1</returns>
        public int Compare(T x, T y)
        {
            // Perform null testing.  A null reference is considered to be less
            // than the other object
            if (x == null && y == null)
                return 0;
            else if (x == null)
                return -1;
            else if (y == null)
                return 1;
            else
            {
                // Variables to store the indicies in the original sort order of each of the objects
                int xIndex = 0;
                int yIndex = 0;

                // Try and get both objects from the _sortOrder collection
                bool xExists = _sortOrder.TryGetValue(x, out xIndex);
                bool yExists = _sortOrder.TryGetValue(y, out yIndex);

                // If one object is not in the list it is considered to be
                // greater than the other object.  Otherwise, compare the two
                // indicies, if the index for object x is less than object y,
                // then x is smaller than y and visa versa.
                if (!xExists && !yExists)
                    return 0;
                else if (!xExists)
                    return 1;
                else if (!yExists)
                    return -1;
                else
                    return xIndex.CompareTo(yIndex);
            }
        }
    }

Since the AribitrarySort class is implemented using a Dictionary, which provides O(1) lookup time, the sorting of lists is extremely quick. For example, sorting a list of one million elements only took 2.6 seconds. For reference, sorting the same list alphabetically using the generic quick sort implemented in the .Net Framework took 1.9 seconds.

            Random random = new Random(DateTime.Now.Millisecond);
            List<string> sortOrder = new List<string>() { "Dog", "Cat", "Fish", "Bird", "Rat", "Monkey", "Frog", "Snake", "Spider", "Lizard", "Rabbit" };
            List<string> arbitrarySortList = new List<string>();
            List<string> quickSortList = new List<string>();
            for (int i = 0; i < 1000000; i++)
            {
                string item = sortOrder[random.Next(0, 9)];
                arbitrarySortList.Add(item);
                quickSortList.Add(item);
            }

            Stopwatch sw = Stopwatch.StartNew();
            arbitrarySortList.Sort(new ArbitrarySort<string>(sortOrder));
            sw.Stop();

            Console.WriteLine("Arbitrary Sort Time: " + sw.ElapsedMilliseconds + " ms");

            sw.Reset();
            sw.Start();
            quickSortList.Sort();
            sw.Stop();

            Console.WriteLine("Quick Sort Time: " + sw.ElapsedMilliseconds + " ms");

            // Output
            // ------
            // Arbitrary Sort Time: 2628 ms
            // Quick Sort Time: 1938 ms
Posted in Sorting. Tags: , . 1 Comment »
Follow

Get every new post delivered to your Inbox.

Join 69 other followers