Click here to Skip to main content
11,709,393 members (48,527 online)
Click here to Skip to main content
Add your own
alternative version

Generic Multi-Field/Property Sorting for Lists of Business Objects

, 13 Feb 2008 CPOL 46.9K 356 70
This article presents a simple and flexible way to sort strongly-typed lists of business objects using multiple properties or fields.
multisortsourceanddemo.zip
MultiSortLib
bin
Debug
MultiSortLib.dll
Release
MultiSortLib.instr.pdb
Properties
HyperPropertyDescriptor
HyperPropertyDescriptor
bin
Release
HyperPropertyDescriptor.csproj.user
Properties
HyperPropertyDescriptorSample
bin
Release
HyperPropertyDescriptor.dll
HyperPropertyDescriptor.pdb
HyperPropertyDescriptorSample.exe
HyperPropertyDescriptorSample.pdb
HyperPropertyDescriptorSample.csproj.user
Properties
MultiSortDemo
bin
Debug
MultiSortDemo.exe
MultiSortDemo.vshost.exe
MultiSortLib.dll
Release
MultiSortDemo.instr.pdb
MultiSortDemo.vshost.exe
MultiSortLib.instr.pdb
Properties
DataSources
WorkItem.datasource
WorkItemPropertyName.datasource
Settings.settings
using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Diagnostics;

// Source code by Owen Emlen (owene_1998@yahoo.com, owen@binarynorthwest.com)

namespace MultiSortDemo
{
    /// <summary>
    /// Stores a "work item" pseudo-business object.  
    /// Lists of work items are sorted to test multi-property sort speed in this demo.
    /// Note the addition of Marc Gravell's HyperTypeDescriptionProvider attribute.  This greatly speeds property
    /// value retrieval speed.  If you like, just for kicks, try removing it and note the relative performance :P
    /// </summary>
    [TypeDescriptionProvider(typeof(Hyper.ComponentModel.HyperTypeDescriptionProvider))]
    public class WorkItem
    {
        public WorkItem() { dtAssigned = DateTime.MinValue; }

        /// <summary>
        /// Stores a mapping between a property name and the underlying field that stores the
        /// property's value.  Could be generated dynamically.
        /// </summary>
        public static PropertyFieldMappings<WorkItem> htPropertyToFieldNameMapping =
          new PropertyFieldMappings<WorkItem>();

        // IMPORTANT NOTE: if we access PROTECTED or PRIVATE *fields*, security is 
        // checked on each value retrieval, slowing everything down.

        // let's make our fields public for demonstration purposes
        public bool fItemFinished;
        public DateTime dtAssigned;
        public DateTime dtItemFinished;
        public string sAssignedTo;
        public string sAssignedBy;
        public int nPriority;

        // Let's throw in an enum field to demonstrate how enums can be sorted by their string representations
        public BoredomRating nTaskBoredom;

        /// <summary>
        /// Gets or sets to whom this work item is assigned
        /// </summary>
        [PropertyFieldName("sAssignedTo")]
        public string AssignedTo
        {
            get { return (sAssignedTo == null) ? "(Unassigned)" : sAssignedTo; }
            set
            {
                if (value == null) sAssignedTo = null;
                else
                {
                    if (sAssignedTo == null)
                    {
                        // new assignment, record the date/time assigned
                        sAssignedTo = value;
                        dtAssigned = DateTime.Now.Date;
                    }
                    else
                    {
                        sAssignedTo = value;
                    }
                }
            }
        }

        /// <summary>
        /// Gets or sets who assigned this work item
        /// </summary>
        [PropertyFieldName("sAssignedBy")]
        public string AssignedBy
        {
            get { return (sAssignedBy == null) ? "(Management)" : sAssignedBy; }
            set { sAssignedBy = value; }
        }

        /// <summary>
        /// Gets or sets the date/time at which this work item was assigned
        /// Default to 1/1/2000 if the work item was never formally assigned
        /// </summary>
        [PropertyFieldName("dtAssigned")]
        public DateTime DateAssigned
        {
            get { return (dtAssigned == DateTime.MinValue) ? new DateTime(2000, 1, 1, 1, 1, 1) : dtAssigned; }
            set { dtAssigned = value; }
        }

        /// <summary>
        /// Gets or sets the priority of the work item
        /// </summary>
        [PropertyFieldName("nPriority")]
        public int Priority
        {
            get { return nPriority; }
            set { nPriority = value; }
        }

        /// <summary>
        /// Gets or sets the anticipated task 'interest' level
        /// </summary>
        [PropertyFieldName("nTaskBoredom")]
        public BoredomRating TaskBoredom
        {
            get { return nTaskBoredom; }
            set
            {
                //if (value == BoredomRating.EvenWorseThanCodingASPWebPages)
                //{
                //    Debug.WriteLine("Stop complaining and get back to work!");
                //    CompanySecurity.ReportSuspiciousActivity("Employee is bored.  Assign more work and dock pay.");
                //}
                nTaskBoredom = value;
            }
        }

        /// <summary>
        /// Gets or sets whether the item has been finished or completed.  
        /// If switching from unfinished to finished, the date/time of completion is recorded.
        /// </summary>
        [PropertyFieldName("fItemFinished")]
        public bool ItemFinished
        {
            get { return fItemFinished; }
            set
            {
                // Completing an unfinished item, record the date/time
                if (!fItemFinished && value == true)
                {
                    dtItemFinished = DateTime.Now.Date;
                    fItemFinished = true;
                }
            }
        }

        // Return the time the item was completed/finished.  If the work item has not
        // been completed, return DateTime.MinValue
        [PropertyFieldName("dtItemFinished")]
        public DateTime DateFinished
        {
            get { return (fItemFinished ? dtItemFinished : DateTime.MinValue); }
        }

        /// <summary>
        /// Method used to alter the work item's assigned date
        /// </summary>
        /// <param name="nDays"></param>
        public void FoundOutAboutWorkItemDaysLater(int nDays)
        {
            dtAssigned = dtAssigned.AddDays(nDays);
        }

        /// <summary>
        /// Method to report the work item was completed several days ago
        /// </summary>
        /// <param name="nDays"></param>
        public void PretendCompleted(int nDays)
        {
            fItemFinished = true;
            dtItemFinished = DateTime.Now.Date.AddDays(-nDays);
        }

        /// <summary>
        /// This would be best done with Attributes on properties, but for demonstration
        /// purposes, the property<->field name link will be hardcoded
        /// </summary>
        public static void SetupQuickAndDirtyPropertyToFieldLinkLookup()
        {
            // In the real world we simply place attributes on the properties when a
            // quick-lookup-by-field is permitted.  Since this is a quick demo, I'm
            // hardcoding the mapping table below...
            // htPropertyToFieldNameMapping.Add("ItemFinished", "fItemFinished");
            // htPropertyToFieldNameMapping.Add("DateFinished", "dtItemFinished");
            // htPropertyToFieldNameMapping.Add("TaskBoredom", "nTaskBoredom");
            // htPropertyToFieldNameMapping.Add("Priority", "nPriority");
            // htPropertyToFieldNameMapping.Add("DateAssigned", "dtAssigned");
            // htPropertyToFieldNameMapping.Add("AssignedTo", "sAssignedTo");
            // htPropertyToFieldNameMapping.Add("AssignedBy", "sAssignedBy");
        }
    }

    /// <summary>
    /// Encapsulates a Work Item property name for easy data binding to UI/controls
    /// </summary>
    public class WorkItemPropertyName
    {
        private string sPropName;
        public string PropertyName { get { return sPropName; } set { sPropName = value; } }
        public WorkItemPropertyName(string sPropertyName) { sPropName = sPropertyName; }
    }

    /// <summary>
    /// Dummy ratings for work items.  Used to demonstrate sorting via enum values
    /// Not placed within the work item class because this may also be used to rate
    /// company social events...
    /// </summary>
    public enum BoredomRating 
    {
        NoRating = 0,
        EvenWorseThanCodingASPWebPages = 1,
        TediusAndDull = 2,
        BarelyTolerable = 3,
        Tolerable = 4,
        SomewhatFun = 5,
        DownrightExciting = 6,
        MaxExcitement = 7
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

owen654321
Software Developer (Senior) Troppus Software
United States United States
Currently working as a Senior Silverlight Developer with Troppus Software in Superior, CO. I enjoy statistics, programming, new technology, playing the cello, and reading codeproject articles. Smile | :)

You may also be interested in...

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150819.1 | Last Updated 13 Feb 2008
Article Copyright 2007 by owen654321
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid