Click here to Skip to main content
15,894,254 members
Articles / Desktop Programming / Windows Forms

Real-Time Data Grid

Rate me:
Please Sign up or sign in to vote.
4.85/5 (47 votes)
29 Sep 20076 min read 165.6K   13.5K   201  
An Excel-style grid displaying data changes in real-time
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.Diagnostics;
using System.Threading;
using System.Globalization;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Windows.Forms;

namespace SKACERO
{
    #region --- Enumerations -----------------------------------------

    public enum SortOrderEnum
    {
        Unsorted = 0,
        Ascending,
        Descending
    }

    #endregion

    #region --- Class ActiveColumnHeader -----------------------------

    /// <summary>
    /// Displays a single column header in a ActiveGrid control
    /// </summary>
    public class ActiveColumnHeader : ColumnHeader
    {
        #region --- Class Data ----------------------------------

        private StringAlignment fldVerticalAlignment;
        private StringAlignment fldHorizontallAlignment;
        private String fldFormat;
        private SortOrderEnum _sortOrder;
        private bool _displayZeroValue;

        #endregion

        #region --- Constructor ---------------------------------

        public ActiveColumnHeader()
            : base()
        {
            // Set the default values
            Initialize();
        }

        public ActiveColumnHeader(int imageIndex)
            : base(imageIndex)
        {
            // Set the default values
            Initialize();
        }

        public ActiveColumnHeader(string imageKey)
            : base(imageKey)
        {
            // Set the default values
            Initialize();
        }

        private void Initialize()
        {
            this.fldHorizontallAlignment = StringAlignment.Center;
            this.fldVerticalAlignment = StringAlignment.Center;
            this.fldFormat = String.Empty;
            this._sortOrder = SortOrderEnum.Unsorted;
            this._displayZeroValue = true;
        }

        #endregion

        #region --- Public Methods ------------------------------

        /// <summary>
        /// Toggle the sort order of this column between ascending and descending.
        /// </summary>
        /// <returns>The new sort order for this column</returns>
        public SortOrderEnum SwitchSortOrder()
        {
            this._sortOrder = (this._sortOrder == SortOrderEnum.Ascending) ? SortOrderEnum.Descending : SortOrderEnum.Ascending;
            return this._sortOrder;
        }

        /// <summary>
        /// Reset this column to its default values.
        /// </summary>
        public void Reset()
        {
            this._sortOrder = SortOrderEnum.Ascending;
        }

        #endregion

        #region --- Cell Appearance Properties ------------------

        [Category("Cell Appearance"),
        DefaultValue(StringAlignment.Center),
        Description("Vertical alignment of the text in all cells belonging to this column"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public StringAlignment CellVerticalAlignment
        {
            get { return this.fldVerticalAlignment;  }
            set { this.fldVerticalAlignment = value; }
        }

        [Category("Cell Appearance"),
        DefaultValue(StringAlignment.Center),
        Description("Horizontal alignment of the text in all cells belonging to this column"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public StringAlignment CellHorizontalAlignment
        {
            get { return this.fldHorizontallAlignment;  }
            set { this.fldHorizontallAlignment = value; }
        }

        [Category("Cell Appearance"),
        DefaultValue(null),
        Description("Format specifier for the text in all cells belonging to this column"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public String CellFormat
        {
            get { return String.IsNullOrEmpty(this.fldFormat) ? String.Empty : this.fldFormat; }
            set { this.fldFormat = value; }
        }



        [Category("Cell Appearance"),
        DefaultValue(true),
        Description("Show or hide the value of zero"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Boolean DisplayZeroValues
        {
            get { return this._displayZeroValue;  }
            set { this._displayZeroValue = value; }

        }

        #endregion

        #region --- Properties ----------------------------------

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public ActiveGrid Grid
        {
            get { return base.ListView as ActiveGrid; }
        }

        public SortOrderEnum SortOrder
        {
            get { return this._sortOrder;  }
            set { this._sortOrder = value; }
        }

        #endregion
    }

    #endregion

    #region --- Class ActiveGrid -------------------------------------

    /// <summary>
    /// Represents a lightweight grid control that supports real-time notification
    /// of cell changes.
    /// ( Based in a standard ListView control in 'Detail View' mode )
    /// </summary>
    public class ActiveGrid : ListView
    {
        #region --- Class Data -----------------------------------------

        private System.ComponentModel.IContainer components = null;
        private ActiveColumnHeaderCollection _lvColumns;
        private ActiveRowCollection _lvRows;
        private bool _layoutSuspended;
        private int _groupIndex;
        private object syncRoot = new object();
        private Dictionary<String, ActiveRow.ActiveCell> _cells = new Dictionary<string, ActiveRow.ActiveCell>();
        private string _mouseOverRowKey = String.Empty;
        private bool _rowHeaderLikeButton = false;

        #region --- Row Values ----------------------------

        private bool fldUseAlternateRow;
        private bool fldUseGradient;

        #endregion

        #region --- Flash Values --------------------------

        private bool fldAllowFlashing;
        private bool fldFlashUseGradient;
        private bool fldFlashFadeEffect;
        private int fldFlashDuration;
        private int _flashCount;
        private Font fldFlashFont;

        #endregion

        #endregion

        #region --- Delegates ------------------------------------------

        public event OnRowHeaderLeftMouseClickHandler OnRowHeaderLeftMouseClick;
        public delegate void OnRowHeaderLeftMouseClickHandler(object sender, RowHeaderEventArgs e);

        public event OnRowHeaderRightMouseClickHandler OnRowHeaderRightMouseClick;
        public delegate void OnRowHeaderRightMouseClickHandler(object sender, RowHeaderEventArgs e);

        #endregion

        #region --- Constructor ----------------------------------------

        public ActiveGrid()
            : base()
        {
            this.components = new System.ComponentModel.Container();

            // This control is only ever intended to be used in the 'Details' view mode
            base.View = System.Windows.Forms.View.Details;

            this._lvColumns = new ActiveColumnHeaderCollection(this);
            this._lvRows = new ActiveRowCollection(this);
            this._layoutSuspended = false;
            this._groupIndex = 0;
            this._flashCount = 0;


            // NON-FLASH Defaults
            this.fldUseAlternateRow = true;
            this.fldUseGradient = false;
            this.fldFlashFadeEffect = false;


            // FLASH Defaults
            this.fldAllowFlashing = false;
            this.fldFlashUseGradient = false;
            this.fldFlashDuration = ActiveRow.ActiveCell.DEFAULT_FLASH_DURATION;
            this.fldFlashFont = this.Font;

            // Activate double buffering
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);

            // Enable the OnNotifyMessage event so we get a chance to filter out 
            // Windows messages before they get to the form's WndProc
            this.SetStyle(ControlStyles.EnableNotifyMessage, true);

            this.OwnerDraw = true;

        }

        public ActiveGrid(IContainer container)
            : this()
        {
            this.components = container;
        }

        #endregion

        #region --- Public Methods -------------------------------------

        /// <summary>
        /// Adds a new column with the specified name to the grid
        /// </summary>
        /// <param name="name">The name associated with the new column</param>
        /// <param name="text">The text to be displayed in the column header</param>
        /// <param name="width">The width of the column</param>
        /// <param name="hAlign">The horizontal alignment of the text in the column header</param>
        /// <param name="value">Object containing data associated with the column header</param>
        /// <returns>The newly created column if successful, otherwise null</returns>
        public ActiveColumnHeader AddColumn(string name, string text, int width, HorizontalAlignment hAlign, object value)
        {
            ActiveColumnHeader newColumn = null;

            // Make sure that a column with this name doesn't already exist.
            if (this.Columns.ContainsKey(name))
                throw new DuplicateColumnNameException(String.Format("{0} : A column with this name already exists", name));

            // Column doesn't already exist so we can add it.
            newColumn = new ActiveColumnHeader();
            if (newColumn != null)
            {
                newColumn.Name = name;
                newColumn.Text = text;
                newColumn.Width = width;
                newColumn.TextAlign = hAlign;
                newColumn.Tag = value;

                this.Columns.Add(newColumn);
            }

            return newColumn;
        }

        /// <summary>
        /// Returns the position of the first row that has a value equal to or greater than 'name'
        /// This is the first position where an element with value 'name' could get inserted 
        /// without breaking the actual sorting of the range.
        /// </summary>
        /// <param name="name">Value to compare</param>
        /// <returns>The position of the first row that has a value equal to or greater than 'name'</returns>
        public int LowerBound(string name)
        {
            int index = 0;
            foreach (ActiveRow itm in this.Items)
            {
                if (String.CompareOrdinal(itm.Text, name) >= 0)
                {
                    index = itm.Index;
                    break;
                }
            }

            return index;
        }

        /// <summary>
        /// Returns the position of the first row that has a value greater than 'name'
        /// This is the last position where an element with value 'name' could get inserted 
        /// without breaking the actual sorting of the range.
        /// </summary>
        /// <param name="name">Value to compare</param>
        /// <returns>The position of the first row that has a value greater than 'name'</returns>
        public int UpperBound(string name)
        {
            int index = 0;
            foreach (ActiveRow itm in this.Items)
            {
                if (String.CompareOrdinal(itm.Text.ToUpper(), name.ToUpper()) > 0)
                {
                    index = itm.Index;
                    break;
                }

                index++;
            }

            return index;
        }

        /// <summary>
        /// Removes the column with the specified name from the grid
        /// </summary>
        /// <param name="name"></param>
        public void RemoveColumn(string name)
        {
            if (this.Columns.ContainsKey(name))
                this.Columns.RemoveByKey(name);
        }

        /// <summary>
        /// Removes the row with the specified name from the grid.
        /// </summary>
        /// <param name="name"></param>
        public void RemoveRow(string name)
        {
            if (this.Items.ContainsKey(name))
                this.Items.RemoveByKey(name);
        }

        /// <summary>
        /// Checks whether a row with the given name exists in the grid.
        /// </summary>
        /// <param name="rowname">The name of the row</param>
        /// <returns>true if the row exists; otherwise, false.</returns>
        public bool RowExists(string rowname)
        {
            return (!String.IsNullOrEmpty(rowname) && this.Items.ContainsKey(rowname));
        }

        /// <summary>
        /// Shows the column with the given name by setting the width to the value provided.
        /// </summary>
        /// <param name="columnname"></param>
        /// <param name="width">The name of the column to show</param>
        public void ShowColumn(string columnname, int width)
        {
            if (width <= 0)
            {
                HideColumn(columnname);
            }
            else if (this.Columns.ContainsKey(columnname))
            {
                ColumnHeader column = this.Columns[this.Columns.IndexOfKey(columnname)];
                if (column != null)
                    column.Width = width;
            }
        }

        /// <summary>
        /// Hides the column with the given name by setting the width to zero.
        /// </summary>
        /// <param name="columnname">The name of the column to hide</param>
        public void HideColumn(string columnname)
        {
            if (this.Columns.ContainsKey(columnname))
            {
                ColumnHeader column = this.Columns[this.Columns.IndexOfKey(columnname)];
                if (column != null)
                    column.Width = 0;
            }
        }

        /// <summary>
        /// Temporarily suspends the layout logic for the grid
        /// </summary>
        public new void SuspendLayout()
        {
            lock (syncRoot)
            {
                this._layoutSuspended = true;

                base.SuspendLayout();

                base.BeginUpdate();
            }
        }

        /// <summary>
        /// Resumes usual layout logic, optionally forcing an immediate layout
        /// of pending layout requests.
        /// </summary>
        /// <param name="performLayout">true to execute bending layout requests; otherwise false</param>
        public new void ResumeLayout(bool performLayout)
        {
            lock (syncRoot)
            {
                this._layoutSuspended = false;

                base.EndUpdate();

                base.ResumeLayout(performLayout);
            }
        }

        /// <summary>
        /// Resumes usual layout logic, optionally forcing an immediate layout
        /// of pending layout requests.
        /// </summary>
        public new void ResumeLayout()
        {
            lock (syncRoot)
            {
                this._layoutSuspended = false;

                base.EndUpdate();

                base.ResumeLayout();
            }
        }

        /// <summary>
        /// Increment the number of cells that are currently in a flashed state
        /// </summary>
        public void IncrementFlashCount()
        {
           Interlocked.Increment(ref this._flashCount);
        }

        /// <summary>
        /// Decrement the number of cells that are currently in a flashed state
        /// </summary>
        public void DecrementFlashCount()
        {
           Interlocked.Decrement(ref this._flashCount);
        }

        public ActiveRow.ActiveCell FindCell(string keyRow, string keyColumn)
        {
            ActiveRow.ActiveCell cell = null;

            if (this._lvRows.ContainsKey(keyRow) && this.Columns.ContainsKey(keyColumn))
            {
                ActiveRow row = this._lvRows[keyRow];
                if (row != null )
                    cell = row.SubItems[this.Columns.IndexOfKey(keyColumn)];
            }

            return cell;
        }

        public ActiveRow.ActiveCell FindCell(string key)
        {
            ActiveRow.ActiveCell cell = null;

            if (!this._cells.TryGetValue(key, out cell))
                cell = null;

            return cell;
        }


        public override string ToString()
        {
            return "ActiveGrid{}";
        }

        #endregion

        #region --- Protected Methods ----------------------------------

        /// <summary>
        /// Invalidates the specific region of the grid and causes a paint message to be sent to the grid.
        /// </summary>
        /// <param name="rc"></param>
        private delegate void InvalidateCallback(Rectangle rc);
        protected new void Invalidate(Rectangle rc)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new InvalidateCallback(Invalidate), new object[] { rc });
                return;
            }

            base.Invalidate(rc, false);
        }

        /// <summary>
        /// Invalidates the specific cell of the grid and causes a paint message to be sent to the grid.
        /// </summary>
        /// <param name="cell"></param>
        private delegate void InvalidateCellCallback(ActiveRow.ActiveCell cell);
        public void InvalidateCell(ActiveRow.ActiveCell cell)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new InvalidateCellCallback(InvalidateCell), new object[] { cell });
                return;
            }

            if (cell != null)
             cell.Draw(base.CreateGraphics());
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="m"></param>
        protected override void OnNotifyMessage(Message m)
        {
            //Filter out the WM_ERASEBKGND message
            if (m.Msg != 0x14)
              base.OnNotifyMessage(m);
        }

        protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
        {
            e.DrawDefault = true;
            base.OnDrawColumnHeader(e);
        }

        protected override void OnDrawItem(DrawListViewItemEventArgs e)
        {
            e.DrawDefault = false;
            ActiveRow row = e.Item as ActiveRow;
            if (row != null)
                row.Draw(e);
        }

        protected override void OnDrawSubItem(DrawListViewSubItemEventArgs e)
        {
            e.DrawDefault = false;
            ActiveRow.ActiveCell cell = e.SubItem as ActiveRow.ActiveCell;
            if (cell != null)
                cell.Draw(e.Graphics, e.Item.Selected);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            ListViewHitTestInfo lvh = this.HitTest(e.Location);
            if (lvh != null)
            {
                ActiveRow row = lvh.Item as ActiveRow;
                if (row != null)
                {
                    // Has the row changed
                    if (this._mouseOverRowKey != row.Name)
                    {
                        ActiveRow rowPrevious = this.Items[this._mouseOverRowKey];
                        if (rowPrevious != null)
                            rowPrevious.OnMouseMove(e);
                    }

                    this._mouseOverRowKey = row.Name;
                    row.OnMouseMove(e);
                }
                else
                {
                    OnRowLeave(e);
                }
            }
            else
            {
                    OnRowLeave(e);
            }
        }

        private void OnRowLeave(MouseEventArgs e)
        {
            if (!String.IsNullOrEmpty(this._mouseOverRowKey))
            {
                ActiveRow rowPrevious = this.Items[this._mouseOverRowKey];
                if (rowPrevious != null)
                    rowPrevious.OnMouseMove(e);
            }

            this._mouseOverRowKey = String.Empty;
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            base.OnMouseLeave(e);

            OnRowLeave(new MouseEventArgs( MouseButtons.None, 0, -1, -1, 0) );
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            bool handled = false;

            ListViewHitTestInfo lvh = this.HitTest(e.Location);
            if (lvh != null)
            {
                ActiveRow row = lvh.Item as ActiveRow;
                if (row != null)
                    handled = row.OnMouseClick(e);
            }

            if(!handled)
              base.OnMouseClick(e);
        }


        public void RowHeaderLeftClick(ActiveRow row)
        {
            if (row != null)
            {
                OnRowHeaderLeftMouseClickHandler onRowHeaderLeftMouseClick = OnRowHeaderLeftMouseClick;
                if (onRowHeaderLeftMouseClick != null)
                    onRowHeaderLeftMouseClick(this, new RowHeaderEventArgs(row.Index, row.Name, row.Tag));
            }
        }

        public void RowHeaderRightClick(ActiveRow row)
        {
            if (row != null)
            {
                OnRowHeaderRightMouseClickHandler onRowHeaderRightMouseClick = OnRowHeaderRightMouseClick;
                if (onRowHeaderRightMouseClick != null)
                    onRowHeaderRightMouseClick(this, new RowHeaderEventArgs(row.Index, row.Name, row.Tag));
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #endregion

        #region --- Appearance Alternating Row Properties --------------

        [Category("Appearance Alternating Row"),
        DefaultValue(true),
        Description("Draw alternating backgrounds"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Boolean UseAlternateRowColors
        {
            get { return this.fldUseAlternateRow; }
            set { this.fldUseAlternateRow = value; }
        }

        [Category("Appearance Alternating Row"),
        DefaultValue(null),
        Description("Background color of alternate rows in the list"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Color AlternatingBackColor
        {
            get { return ActiveGrid.Paintbox.AlternateBackgroundColor;  }
            set { ActiveGrid.Paintbox.AlternateBackgroundColor = value; }
        }

        [Category("Appearance Alternating Row"),
        DefaultValue(false),
        Description("Draw backgrounds using a gradient"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Boolean UseGradient
        {
            get { return this.fldUseGradient;  }
            set { this.fldUseGradient = value; }
        }

        [Category("Appearance Alternating Row"),
        DefaultValue(LinearGradientMode.Vertical),
        Description("Direction of the background gradient"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public LinearGradientMode LinearGradientMode
        {
            get { return ActiveGrid.Paintbox.RowLinearGradientMode; }
            set { ActiveGrid.Paintbox.RowLinearGradientMode = value; }
        }

        [Category("Appearance Alternating Row"),
        DefaultValue(null),
        Description("Start Color of the alternating background gradient"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Color AlternatingGradientStartColor
        {
            get { return ActiveGrid.Paintbox.GradientStartColor;  }
            set { ActiveGrid.Paintbox.GradientStartColor = value; }
        }

        [Category("Appearance Alternating Row"),
        DefaultValue(null),
        Description("End Color of the alternating background gradient"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Color AlternatingGradientEndColor
        {
            get { return ActiveGrid.Paintbox.GradientEndColor;  }
            set { ActiveGrid.Paintbox.GradientEndColor = value; }
        }

        #endregion

        #region --- Flash Behaviour Properties -------------------------

        [Category("Flash Behavior"),
        DefaultValue(null),
        Description("Flash the cell when its contents are changed"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Boolean AllowFlashing
        {
            get { return this.fldAllowFlashing;  }
            set { this.fldAllowFlashing = value; }
        }

        [Category("Flash Behavior"),
        DefaultValue(false),
        Description("Draw gradient backgrounds for flashed cells"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Boolean UseFlashGradient
        {
            get { return this.fldFlashUseGradient;  }
            set { this.fldFlashUseGradient = value; }
        }

        [Category("Flash Behavior"),
        DefaultValue(false),
        Description("Fade-out effect for flashed cells"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Boolean UseFlashFadeOut
        {
            get { return this.fldFlashFadeEffect; }
            set { this.fldFlashFadeEffect = value; }
        }       

        [Category("Flash Behavior"),
        DefaultValue(null),
        Description("Length of time in milliseconds that a cell remains in the flashed state"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Int32 FlashDuration
        {
            get { return this.fldFlashDuration;  }
            set { this.fldFlashDuration = value; }
        }

        [Category("Flash Behavior"),
        DefaultValue(null),
        Description("Color of the text when a cell is in the flashed state"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Color FlashForeColor
        {
            get { return ActiveGrid.Paintbox.FlashForeColor;  }
            set { ActiveGrid.Paintbox.FlashForeColor = value; }
        }

        [Category("Flash Behavior"),
        DefaultValue(null),
        Description("Color of the background when a cell is in the flashed state"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Color FlashBackColor
        {
            get { return ActiveGrid.Paintbox.FlashBackgroundColor;  }
            set { ActiveGrid.Paintbox.FlashBackgroundColor = value; }
        }

        [Category("Flash Behavior"),
        DefaultValue(null),
        Description("Font used when a cell is in the flashed state"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Font FlashFont
        {
            get { return this.fldFlashFont;  }
            set { this.fldFlashFont = value; }
        }

        [Category("Flash Behavior"),
        DefaultValue(null),
        Description("Start Color of the background gradient when a cell is in the flashed state"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Color FlashGradientStartColor
        {
            get { return ActiveGrid.Paintbox.FlashGradientStartColor;  }
            set { ActiveGrid.Paintbox.FlashGradientStartColor = value; }
        }

        [Category("Flash Behavior"),
        DefaultValue(null),
        Description("End Color of the background gradient when a cell is in the flashed state"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Color FlashGradientEndColor
        {
            get { return ActiveGrid.Paintbox.FlashGradientEndColor;  }
            set { ActiveGrid.Paintbox.FlashGradientEndColor = value; }
        }

        [Category("Flash Behavior"),
        DefaultValue(LinearGradientMode.Vertical),
        Description("Direction of the Background gradient for flashed cells"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public LinearGradientMode FlashLinearGradientMode
        {
            get { return ActiveGrid.Paintbox.FlashLinearGradientMode;  }
            set { ActiveGrid.Paintbox.FlashLinearGradientMode = value; }
        }

        #endregion

        #region --- Public Properties ----------------------------------

        public new Color BackColor
        {
            get { return ActiveGrid.Paintbox.NormalBackgroundColor;  }
            set { ActiveGrid.Paintbox.NormalBackgroundColor = value; }
        }

        [Category("Appearance"),
        DefaultValue(null),
        Description("Fore color for negative numeric values"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Color ForeColorNegativeValues
        {
            get { return ActiveGrid.Paintbox.NegativeValueColor;  }
            set { ActiveGrid.Paintbox.NegativeValueColor = value; }
        }

        [Category("Appearance"),
        DefaultValue(System.Windows.Forms.View.Details),
        Description("Forces the view-style to be set to Details"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public new System.Windows.Forms.View View
        {
            get {  return System.Windows.Forms.View.Details;  }
            set {  base.View = System.Windows.Forms.View.Details; }
        }

        /// <summary>
        /// Flag to indicate if the Row Header labels should behave like 
        /// a LinkLabel control.
        /// </summary>
        [Category("Behavior"),
        DefaultValue(false),
        Description("The ActiveRow labels behave like a linkLabel control"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public Boolean UseRowHeaderButtons
        {
            get { return this._rowHeaderLikeButton;  }
            set { this._rowHeaderLikeButton = value; }
        }

        /// <summary>
        /// An ActiveColumnCollection representing the collection of 
        /// ActiveColumn contained within the ActiveGrid
        /// </summary>
        [Category("Behavior"),
        DefaultValue(null),
        Description("The ActiveColumnHeader controls contained in the ActiveGrid"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public new ActiveColumnHeaderCollection Columns
        {
            get { return this._lvColumns; }
        }

        /// <summary>
        /// An ActiveRowCollection representing the collection of 
        /// ActiveRow objectss contained within the ActiveGrid
        /// </summary>
        [Category("Behavior"),
        DefaultValue(null),
        Description("The ActiveRow items contained in the ActiveGrid"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public new ActiveRowCollection Items
        {
            get { return this._lvRows; }
        }

        public Int32 GroupIndex
        {
            get { return this._groupIndex; }
            set { this._groupIndex = value; }
        }

        /// <summary>
        /// Fetches the cell at the given coordinates
        /// </summary>
        /// <param name="row">Row number index</param>
        /// <param name="column">Column number index</param>
        /// <returns>The ActiveCell object representing the selected cell if successful, otherwise null</returns>
        public ActiveRow.ActiveCell this[int row, int column]
        {
            get { return this[row][column]; }
        }

        /// <summary>
        /// Fetches the row at the given index
        /// </summary>
        /// <param name="index">Row number index</param>
        /// <returns>The ActiveRow object representing the selected row if successful, otherwise null</returns>
        public ActiveRow this[int index]
        {
            get
            {
                if (index >= 0 && index < this.Items.Count)
                    return this.Items[index] as ActiveRow;
                else
                    throw (new IndexOutOfRangeException(String.Format("The row index [{0}] is out of range", index)));
            }
        }

        public Boolean LayoutSuspended
        {
            get { return this._layoutSuspended; }
        }

        public Int32 FlashedCellCount
        {
            get { lock (syncRoot) { return this._flashCount; } }
        }

        #endregion

        #region --- Nested Class ActiveRowCollection -------------------

        /// <summary>
        /// Represents the collection of items in a ActiveGrid control or assigned to a ListViewGroup. 
        /// </summary>
        public class ActiveRowCollection : ListView.ListViewItemCollection
        {
            #region --- Class Data ---------------------------------

            private ActiveGrid _owner;

            #endregion

            #region --- Constructor --------------------------------

            /// <summary>
            /// Initializes a new instance of the ActiveGrid.ActiveRowCollection class
            /// </summary>
            /// <param name="owner">An ActiveGrid representing the grid that owns 
            /// the Control collection</param>
            public ActiveRowCollection(ActiveGrid owner)
                : base(owner)
            {
                if (owner == null)
                    throw new NullReferenceException("ActiveRowCollection: Owner must not be a null value");

                this._owner = owner;
            }

            #endregion

            #region --- Public Methods -----------------------------

            /// <summary>
            /// Adds an existing ActiveRow to the collection.
            /// </summary>
            /// <param name="value">The ActiveRow to add to the collection</param>
            /// <returns>The ActiveRow that was added to the collection</returns>
            public ActiveRow Add(ActiveRow value)
            {
                ActiveRow row = base.Add(value) as ActiveRow;

                if (row != null)
                {
                    for (int i = 1; i < row.SubItems.Count; i++)
                    {
                        ActiveRow.ActiveCell cell = row[i];
                        if (!String.IsNullOrEmpty(cell.Name))
                            this._owner._cells.Add(cell.Name, cell);
                    }
                }

                return row;
            }

            /// <summary>
            /// Adds an item to the collection with the specified text.
            /// </summary>
            /// <param name="text">The text to display for the item.</param>
            /// <returns>The ActiveRow that was added to the collection</returns>
            public new ActiveRow Add(string text)
            {
                return base.Add(new ActiveRow(text)) as ActiveRow;
            }

            /// <summary>
            /// Adds an item to the collection with the specified text and image.
            /// </summary>
            /// <param name="text">The text of the item.</param>
            /// <param name="imageIndex">The index of the image to display for the item.</param>
            /// <returns></returns>
            public new ActiveRow Add(string text, int imageIndex)
            {
                return base.Add(new ActiveRow(text, imageIndex)) as ActiveRow;
            }

            /// <summary>
            /// Creates an item with the specified text and image and adds it to the collection. 
            /// </summary>
            /// <param name="text">The text of the item.</param>
            /// <param name="imageKey">The key of the image to display for the item.</param>
            /// <returns>The ActiveRow added to the collection.</returns>
            public new ActiveRow Add(string text, string imageKey)
            {
                return base.Add(new ActiveRow(text, imageKey)) as ActiveRow;
            }

            /// <summary>
            /// Creates an item with the specified key, text, and image and adds an item to the collection. 
            /// </summary>
            /// <param name="key">The name of the item</param>
            /// <param name="text">The text of the item</param>
            /// <param name="imageIndex">The index of the image to display for the item</param>
            /// <returns>The ListViewItem added to the collection</returns>
            public new ActiveRow Add(string key, string text, int imageIndex)
            {
                return base.Add(new ActiveRow(key, text, imageIndex)) as ActiveRow;
            }

            /// <summary>
            /// Creates and item with the specified key, text, and image, and adds it to the collection. 
            /// </summary>
            /// <param name="key">The name of the item</param>
            /// <param name="text">The text of the item</param>
            /// <param name="imageKey">The key of the image to display for the item</param>
            /// <returns>The ActiveRow added to the collection</returns>
            public new ActiveRow Add(string key, string text, string imageKey)
            {
                return base.Add(new ActiveRow(key, text, imageKey)) as ActiveRow;
            }

            /// <summary>
            /// Adds a collection of items to the collection.
            /// </summary>
            /// <param name="items">The ActiveGrid.ActiveRowCollection to add to the collection.</param>
            public void AddRange(ActiveRowCollection items)
            {
                base.AddRange(items);

                foreach (ActiveRow row in items)
                {
                    for (int i = 1; i < row.SubItems.Count; i++)
                    {
                        ActiveRow.ActiveCell cell = row[i];
                        if (!String.IsNullOrEmpty(cell.Name))
                            this._owner._cells.Add(cell.Name, cell);
                    }
                }
            }

            /// <summary>
            /// Adds an array of ActiveRow objects to the collection.
            /// </summary>
            /// <param name="values">An array of ActiveRow objects to add to the collection.</param>
            public void AddRange(ActiveRow[] items)
            {
                base.AddRange(items);

                foreach (ActiveRow row in items)
                {
                    for(int i=1; i< row.SubItems.Count; i++ )
                    {
                        ActiveRow.ActiveCell cell = row[i];
                        if(!String.IsNullOrEmpty(cell.Name))
                            this._owner._cells.Add(cell.Name, cell);
                    }
                }
            }

            /// <summary>
            /// Determines whether the specified item is located in the collection
            /// </summary>
            /// <param name="subItem">An ActiveRow representing the item to locate in the collection</param>
            /// <returns>true if the item is contained in the collection; otherwise, false</returns>
            public bool Contains(ActiveRow item)
            {
                return base.Contains(item);
            }

            /// <summary>
            /// 
            /// </summary>
            /// <param name="key">The item name to search for</param>
            /// <param name="searchAllSubItems">true to search subitems; otherwise, false</param>
            /// <returns>An array of type ListViewItem</returns>
            public new ActiveRow[] Find(string key, bool searchAllSubItems)
            {
                return base.Find(key, searchAllSubItems) as ActiveRow[];
            }

            /// <summary>
            /// Inserts an existing ActiveRow into the collection at the specified index
            /// </summary>
            /// <param name="index">The zero-based index location where the item is inserted</param>
            /// <param name="item">The ActiveRow that represents the item to insert</param>
            /// <returns></returns>
            public ActiveRow Insert(int index, ActiveRow item)
            {
                return base.Insert(index, item) as ActiveRow;
            }

            /// <summary>
            /// Creates a new item and inserts it into the collection at the specified index
            /// </summary>
            /// <param name="index">The zero-based index location where the item is inserted</param>
            /// <param name="text">The text to display for the item</param>
            /// <returns>The ActiveRow that was inserted into the collection</returns>
            public new ActiveRow Insert(int index, string text)
            {
                return base.Insert(index, text) as ActiveRow;
            }

            /// <summary>
            /// Creates a new item with the specified image index and inserts it into the collection at the specified index.
            /// </summary>
            /// <param name="index">The zero-based index location where the item is inserted</param>
            /// <param name="text">The text to display for the item</param>
            /// <param name="imageIndex">The index of the image to display for the item</param>
            /// <returns>The ActiveRow that was inserted into the collection</returns>
            public new ActiveRow Insert(int index, string text, int imageIndex)
            {
                return base.Insert(index, text, imageIndex) as ActiveRow;
            }

            /// <summary>
            /// Creates a new item with the specified text and image and inserts it in the collection at the specified index
            /// </summary>
            /// <param name="index">The zero-based index location where the item is inserted</param>
            /// <param name="text">The text of the ListViewItem</param>
            /// <param name="imageKey">The key of the image to display for the item</param>
            /// <returns>The ActiveRow added to the collection</returns>
            public new ActiveRow Insert(int index, string text, string imageKey)
            {
                return base.Insert(index, text, imageKey) as ActiveRow;
            }

            /// <summary>
            /// Creates a new item with the specified key, text, and image, and inserts it in the collection at the specified index
            /// </summary>
            /// <param name="index">The zero-based index location where the item is inserted</param>
            /// <param name="key">The Name of the item</param>
            /// <param name="text">The text of the item</param>
            /// <param name="imageIndex">The index of the image to display for the item</param>
            /// <returns>The ActiveRow added to the collection</returns>
            public new ActiveRow Insert(int index, string key, string text, int imageIndex)
            {
                return base.Insert(index, key, text, imageIndex) as ActiveRow;
            }

            /// <summary>
            /// Creates a new item with the specified key, text, and image, and adds it to the collection at the specified index
            /// </summary>
            /// <param name="index">The zero-based index location where the item is inserted</param>
            /// <param name="key">The Name of the item</param>
            /// <param name="text">The text of the item</param>
            /// <param name="imageKey">The key of the image to display for the item</param>
            /// <returns>The ListViewItem added to the collection</returns>
            public new ActiveRow Insert(int index, string key, string text, string imageKey)
            {
                return base.Insert(index, key, text, imageKey) as ActiveRow;
            }

            #endregion

            #region --- Public Properties --------------------------

            /// <summary>
            /// Gets or sets the item at the specified index within the collection.
            /// </summary>
            /// <param name="index">The index of the item in the collection to get or set</param>
            public new ActiveRow this[int index]
            {
                get { return base[index] as ActiveRow; }
                set { base[index] = value; }
            }

            /// <summary>
            /// Retrieves the item with the specified key.
            /// </summary>
            /// <param name="key">The name of the item to retrieve.</param>
            public new ActiveRow this[string key]
            {
                get { return base[key] as ActiveRow; }
            }

            #endregion
        }
        #endregion

        #region --- Nested Class ActiveColumnHeaderCollection ----------

        /// <summary>
        /// Represents the collection of column headers in an ActiveGrid control.
        /// </summary>
        public class ActiveColumnHeaderCollection : ListView.ColumnHeaderCollection
        {
            #region --- Class Data ---------------------------------

            private ActiveGrid _owner;

            #endregion

            #region --- Public Constructors ------------------------

            /// <summary>
            /// Initializes a new instance of the ActiveGrid.ActiveColumnHeaderCollection class
            /// </summary>
            /// <param name="owner">An ActiveGrid representing the grid that owns the Control collection</param>
            public ActiveColumnHeaderCollection(ActiveGrid owner)
                : base(owner)
            {
                if (owner == null)
                    throw new NullReferenceException("ActiveColumnHeaderCollection: Owner must not be a null value");

                this._owner = owner;
            }

            #endregion

            #region --- Public Methods -----------------------------

            /// <summary>
            /// Adds an existing ActiveColumnHeader to the collection
            /// </summary>
            /// <param name="value">The ActiveColumnHeader to add to the collection</param>
            /// <returns>The zero-based index into the collection where the item was added</returns>
            public int Add(ActiveColumnHeader value)
            {
                return base.Add(value);
            }

            /// <summary>
            /// Creates and adds a column with the specified text to the collection
            /// </summary>
            /// <param name="text">The text to display in the column header</param>
            /// <returns>The ActiveColumnHeader with the specified text that was added to the ActiveColumnHeaderCollection.</returns>
            public new ActiveColumnHeader Add(string text)
            {
                return base.Add(text) as ActiveColumnHeader;
            }

            /// <summary>
            /// Creates and adds a column with the specified text and width to the collection
            /// </summary>
            /// <param name="text">The text of the ActiveColumnHeader to add to the collection</param>
            /// <param name="width">The width of the ActiveColumnHeader to add to the collection</param>
            /// <returns>The ActiveColumnHeader with the specified text and width that was added to the ActiveColumnHeaderCollection. </returns>
            public new ActiveColumnHeader Add(string text, int width)
            {
                return base.Add(text, width) as ActiveColumnHeader;
            }

            /// <summary>
            /// Creates and adds a column with the specified text and key to the collection.
            /// </summary>
            /// <param name="key">The key of the ActiveColumnHeader to add to the collection</param>
            /// <param name="text">The text of the ActiveColumnHeader to add to the collection</param>
            /// <returns>The ActiveColumnHeader with the specified key and text that was added to the ActiveColumnHeaderCollection</returns>
            public new ActiveColumnHeader Add(string key, string text)
            {
                return base.Add(key, text) as ActiveColumnHeader;
            }

            /// <summary>
            /// Adds a column header to the collection with specified text, width, and alignment settings
            /// </summary>
            /// <param name="text">The text to display in the column header</param>
            /// <param name="width">The initial width of the column header</param>
            /// <param name="textAlign">One of the HorizontalAlignment values</param>
            /// <returns>The ColumnHeader that was created and added to the collection</returns>
            public new ActiveColumnHeader Add(string text, int width, HorizontalAlignment textAlign)
            {
                return base.Add(text, width, textAlign) as ActiveColumnHeader;
            }

            /// <summary>
            /// Creates and adds a column with the specified text, key, and width to the collection
            /// </summary>
            /// <param name="key">The key of the column header</param>
            /// <param name="text">The text to display in the column header</param>
            /// <param name="width">The initial width of the ActiveColumnHeader</param>
            /// <returns>The ActiveColumnHeader with the given text, key, and width that was added to the collection</returns>
            public new ActiveColumnHeader Add(string key, string text, int width)
            {
                return base.Add(key, text, width) as ActiveColumnHeader;
            }

            /// <summary>
            /// Creates and adds a column with the specified key, aligned text, width, and image index to the collection
            /// </summary>
            /// <param name="key">The key of the column header</param>
            /// <param name="text">The text to display in the column header</param>
            /// <param name="width">The initial width of the column header</param>
            /// <param name="textAlign">One of the HorizontalAlignment values</param>
            /// <param name="imageIndex">The index value of the image to display in the column</param>
            /// <returns>The ActiveColumnHeader with the specified key, aligned text, width, and image index that has been added to the collection</returns>
            public new ActiveColumnHeader Add(string key, string text, int width, HorizontalAlignment textAlign, int imageIndex)
            {
                return base.Add(key, text, width, textAlign, imageIndex) as ActiveColumnHeader;
            }

            /// <summary>
            /// Creates and adds a column with the specified key, aligned text, width, and image key to the collection
            /// </summary>
            /// <param name="key">The key of the column header</param>
            /// <param name="text">The text to display in the column header</param>
            /// <param name="width">The initial width of the column header</param>
            /// <param name="textAlign">One of the HorizontalAlignment values</param>
            /// <param name="imageKey">The key value of the image to display in the column header</param>
            /// <returns>The ActiveColumnHeader with the specified key, aligned text, width, and image key that has been added to the collection</returns>
            public new ActiveColumnHeader Add(string key, string text, int width, HorizontalAlignment textAlign, string imageKey)
            {
                return base.Add(key, text, width, textAlign, imageKey) as ActiveColumnHeader;
            }

            /// <summary>
            /// Adds an array of column headers to the collection
            /// </summary>
            /// <param name="values">An array of ActiveColumnHeader objects to add to the collection</param>
            public void AddRange(ActiveColumnHeader[] values)
            {
                base.AddRange(values);
            }

            /// <summary>
            /// Inserts an existing column header into the collection at the specified index
            /// </summary>
            /// <param name="index">The zero-based index location where the column header is inserted</param>
            /// <param name="value">The ActiveColumnHeader to insert into the collection</param>
            public void Insert(int index, ActiveColumnHeader value)
            {
                base.Insert(index, value);
            }

            /// <summary>
            /// Determines whether the specified column header is located in the collection.
            /// </summary>
            /// <param name="value"></param>
            /// <returns></returns>
            public bool Contains(ActiveColumnHeader value)
            {
                return base.Contains(value);
            }


            #endregion

            #region --- Public Properties --------------------------

            /// <summary>
            /// Gets the column header at the specified index within the collection.
            /// </summary>
            /// <param name="index">The index of the column header to retrieve from the collection.</param>
            public new ActiveColumnHeader this[int index]
            {
                get { return base[index] as ActiveColumnHeader; }
            }

            /// <summary>
            /// Gets the column header with the specified key from the collection.
            /// </summary>
            /// <param name="index">The name of the column header to retrieve from the collection</param>
            public new ActiveColumnHeader this[string key]
            {
                get { return base[key] as ActiveColumnHeader;  }
            }

            /// <summary>
            /// Gets the ActiveGrid to which this column belongs.
            /// </summary>
            public ActiveGrid Grid
            {
                get { return this._owner; }
            }

            #endregion
        }

        #endregion

        #region --- Nested Class Paintbox ------------------------------

        /// <summary>
        /// The ActiveGrid can be quite heavy on system resources, especially
        /// in its use of brushes. In an attempt to reduce the number of resources
        /// being created and destroyed, and to reduce the load on the Garbage Collector,
        /// this class is used as a central repository for all of the brushes and colours
        /// required by the control.
        /// </summary>
        public static class Paintbox
        {
            #region --- Custom Brushes ----------------------------

            private static object syncLock = new Object();
            private static Dictionary<System.Drawing.Color, System.Drawing.Brush> _brushes = new Dictionary<System.Drawing.Color, System.Drawing.Brush>(10);

            public static System.Drawing.Brush Brush(System.Drawing.Color color)
            {
                lock (syncLock)
                {
                    System.Drawing.Brush brush = null;

                    if (!_brushes.TryGetValue(color, out brush))
                    {
                        brush = new System.Drawing.SolidBrush(color);
                        _brushes.Add(color, brush);
                    }

                    return brush;
                }
            }

            #endregion

            #region --- Gradients ---------------------------------

            private static System.Drawing.Drawing2D.LinearGradientMode _flashLinearGradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical;
            public static System.Drawing.Drawing2D.LinearGradientMode FlashLinearGradientMode
            {
                get { return _flashLinearGradientMode; }
                set { _flashLinearGradientMode = value; }
            }

            private static System.Drawing.Drawing2D.LinearGradientMode _rowLinearGradientMode = System.Drawing.Drawing2D.LinearGradientMode.Vertical;
            public static System.Drawing.Drawing2D.LinearGradientMode RowLinearGradientMode
            {
                get { return _rowLinearGradientMode; }
                set { _rowLinearGradientMode = value; }
            }

            #endregion

            #region --- Colours -----------------------------------

            private static System.Drawing.Color _clrNormalBackground = System.Drawing.Color.White;
            public static System.Drawing.Color NormalBackgroundColor
            {
                get { return _clrNormalBackground; }
                set { _clrNormalBackground = value; }
            }

            private static System.Drawing.Color _clrAlternateBackground = System.Drawing.Color.Gainsboro;
            public static System.Drawing.Color AlternateBackgroundColor
            {
                get { return _clrAlternateBackground; }
                set { _clrAlternateBackground = value; }
            }



            private static System.Drawing.Color _clrFlashBackground = System.Drawing.Color.Yellow;
            public static System.Drawing.Color FlashBackgroundColor
            {
                get { return _clrFlashBackground; }
                set { _clrFlashBackground = value; }
            }

            private static System.Drawing.Color _clrFlashForeground = System.Drawing.Color.Black;
            public static System.Drawing.Color FlashForeColor
            {
                get { return _clrFlashForeground; }
                set { _clrFlashForeground = value; }
            }

            private static System.Drawing.Color _clrFlashGradientStart = System.Drawing.Color.White;
            public static System.Drawing.Color FlashGradientStartColor
            {
                get { return _clrFlashGradientStart; }
                set { _clrFlashGradientStart = value; }
            }

            private static System.Drawing.Color _clrFlashGradientEnd = System.Drawing.Color.White;
            public static System.Drawing.Color FlashGradientEndColor
            {
                get { return _clrFlashGradientEnd; }
                set { _clrFlashGradientEnd = value; }
            }

            private static System.Drawing.Color _clrGradientStart = System.Drawing.Color.White;
            public static System.Drawing.Color GradientStartColor
            {
                get { return _clrGradientStart; }
                set { _clrGradientStart = value; }
            }

            private static System.Drawing.Color _clrGradientEnd = System.Drawing.Color.White;
            public static System.Drawing.Color GradientEndColor
            {
                get { return _clrGradientEnd; }
                set { _clrGradientEnd = value; }
            }

            private static System.Drawing.Color _clrNegativeForeground = System.Drawing.Color.Red;
            public static System.Drawing.Color NegativeValueColor
            {
                get { return _clrNegativeForeground; }
                set { _clrNegativeForeground = value; }
            }

            private static System.Drawing.Color _clrPreTextForeground = System.Drawing.Color.Black;
            public static System.Drawing.Color PreTextColor
            {
                get { return _clrPreTextForeground; }
                set { _clrPreTextForeground = value; }
            }


            private static System.Drawing.Color _clrPostTextForeground = System.Drawing.Color.Black;
            public static System.Drawing.Color PostTextColor
            {
                get { return _clrPostTextForeground; }
                set { _clrPostTextForeground = value; }
            }


            private static System.Drawing.Color _clrFlashPreTextForeground = System.Drawing.Color.Black;
            public static System.Drawing.Color FlashPreTextColor
            {
                get { return _clrFlashPreTextForeground; }
                set { _clrFlashPreTextForeground = value; }
            }


            private static System.Drawing.Color _clrFlashPostTextForeground = System.Drawing.Color.Black;
            public static System.Drawing.Color FlashPostTextColor
            {
                get { return _clrFlashPostTextForeground; }
                set { _clrFlashPostTextForeground = value; }
            }

            private static System.Drawing.Color _clrNormalTextForeground = System.Drawing.Color.Black;
            public static System.Drawing.Color NormalTextColor
            {
                get { return _clrNormalTextForeground; }
                set { _clrNormalTextForeground = value; }
            }

            #endregion

            #region --- Brushes -----------------------------------

            private static System.Drawing.SolidBrush _brushNormalBackground;
            public static System.Drawing.Brush NormalBackgroundBrush
            {
                get
                {
                    if (_brushNormalBackground == null)
                        _brushNormalBackground = new System.Drawing.SolidBrush(_clrNormalBackground);
                    else if (_brushNormalBackground.Color != _clrNormalBackground)
                    {
                        _brushNormalBackground.Color = _clrNormalBackground;
                    }

                    return _brushNormalBackground;
                }
            }

            private static System.Drawing.SolidBrush _brushAlternateBackground;
            public static System.Drawing.Brush AlternateBackgroundBrush
            {
                get
                {
                    if (_brushAlternateBackground == null)
                        _brushAlternateBackground = new System.Drawing.SolidBrush(_clrAlternateBackground);
                    else if (_brushAlternateBackground.Color != _clrAlternateBackground)
                    {
                        _brushAlternateBackground.Color = _clrAlternateBackground;
                    }

                    return _brushAlternateBackground;
                }
            }

            private static System.Drawing.SolidBrush _brushFlashBackground;
            public static System.Drawing.Brush FlashBackgroundBrush
            {
                get
                {
                    if (_brushFlashBackground == null)
                        _brushFlashBackground = new System.Drawing.SolidBrush(_clrFlashBackground);
                    else if (_brushFlashBackground.Color != _clrFlashBackground)
                    {
                        _brushFlashBackground.Color = _clrFlashBackground;
                    }

                    return _brushFlashBackground;
                }
            }

            private static System.Drawing.SolidBrush _brushFlashText;
            public static System.Drawing.Brush FlashTextBrush
            {
                get
                {
                    if (_brushFlashText == null)
                        _brushFlashText = new System.Drawing.SolidBrush(_clrFlashForeground);
                    else if (_brushFlashText.Color != _clrFlashForeground)
                    {
                        _brushFlashText.Color = _clrFlashForeground;
                    }

                    return _brushFlashText;
                }
            }


            private static System.Drawing.SolidBrush _brushNormalText;
            public static System.Drawing.Brush NormalTextBrush
            {
                get
                {
                    if (_brushNormalText == null)
                        _brushNormalText = new System.Drawing.SolidBrush(_clrNormalTextForeground);
                    else if (_brushNormalText.Color != _clrNormalTextForeground)
                    {
                        _brushNormalText.Color = _clrNormalTextForeground;
                    }

                    return _brushNormalText;
                }
            }


            private static System.Drawing.SolidBrush _brushNegativeText;
            public static System.Drawing.Brush NegativeValueBrush
            {
                get
                {
                    if (_brushNegativeText == null)
                        _brushNegativeText = new System.Drawing.SolidBrush(_clrNegativeForeground);
                    else if (_brushNegativeText.Color != _clrNegativeForeground)
                    {
                        _brushNegativeText.Color = _clrNegativeForeground;
                    }

                    return _brushNegativeText;
                }
            }


            private static System.Drawing.SolidBrush _brushPreText;
            public static System.Drawing.Brush PreTextBrush
            {
                get
                {
                    if (_brushPreText == null)
                        _brushPreText = new System.Drawing.SolidBrush(_clrPreTextForeground);
                    else if (_brushPreText.Color != _clrPreTextForeground)
                    {
                        _brushPreText.Color = _clrPreTextForeground;
                    }

                    return _brushPreText;
                }
            }


            private static System.Drawing.SolidBrush _brushPostText;
            public static System.Drawing.Brush PostTextBrush
            {
                get
                {
                    if (_brushPostText == null)
                        _brushPostText = new System.Drawing.SolidBrush(_clrPostTextForeground);
                    else if (_brushPostText.Color != _clrPostTextForeground)
                    {
                        _brushPostText.Color = _clrPostTextForeground;
                    }

                    return _brushPostText;
                }
            }

            private static System.Drawing.SolidBrush _brushFlashPreText;
            public static System.Drawing.Brush FlashPreTextBrush
            {
                get
                {
                    if (_brushFlashPreText == null)
                        _brushFlashPreText = new System.Drawing.SolidBrush(_clrFlashPreTextForeground);
                    else if (_brushFlashPreText.Color != _clrFlashPreTextForeground)
                    {
                        _brushFlashPreText.Color = _clrFlashPreTextForeground;
                    }

                    return _brushFlashPreText;
                }
            }


            private static System.Drawing.SolidBrush _brushFlashPostText;
            public static System.Drawing.Brush FlashPostTextBrush
            {
                get
                {
                    if (_brushFlashPostText == null)
                        _brushFlashPostText = new System.Drawing.SolidBrush(_clrFlashPostTextForeground);
                    else if (_brushFlashPostText.Color != _clrFlashPostTextForeground)
                    {
                        _brushFlashPostText.Color = _clrFlashPostTextForeground;
                    }

                    return _brushFlashPostText;
                }
            }


            #endregion
        }

        #endregion
    }

    #endregion

    #region --- Class ActiveRow --------------------------------------

    /// <summary>
    /// Class representing a row within the ActiveGrid
    /// </summary>
    public class ActiveRow : ListViewItem
    {
        #region --- Enumerations ----------------------------------

        public enum CellStyle
        {
            Plain = 0,
            Gradient
        }

        public enum CellState
        {
            Normal = 0,
            Highlighted,
            Flashed
        }

        #endregion

        #region --- Class Data ------------------------------------

        /// <summary>
        /// The collection of ActiveCells belonging to this row.
        /// </summary>
        private ActiveCellCollection _cells;
        /// <summary>
        /// Synchronization object
        /// </summary>
        private object syncRoot = new object();
        /// <summary>
        /// Row header LinkLabel
        /// </summary>
        private LinkLabelCell _linkLabel;

        #endregion

        #region --- Overloaded Constructors -----------------------

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with default values. 
        /// </summary>
        public ActiveRow()
            : base()
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the specified item text. 
        /// </summary>
        /// <param name="text">The text to display for the item</param>
        public ActiveRow(string text)
            : base(text)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with an array of strings representing subitems.
        /// </summary>
        /// <param name="items">An array of strings that represent the subitems of the new item.</param>
        public ActiveRow(string[] items)
            : base(items)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with an array of ActiveCell objects and the image 
        /// index position of the item's icon. 
        /// </summary>
        /// <param name="subItems">An array of type ActiveCell that represents the subitems of the item. </param>
        /// <param name="imageIndex">The zero-based index of the image within the ImageList associated with the ListView that contains the item.</param>
        public ActiveRow(ActiveCell[] subItems, int imageIndex)
            : base(subItems, imageIndex)
        {
            Initialize();
        }


        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the specified item text and the image index position of the item's icon. 
        /// </summary>
        /// <param name="text">The text to display for the item.</param>
        /// <param name="imageIndex">The zero-based index of the image within the ImageList associated with the ListView that contains the item.</param>
        public ActiveRow(string text, int imageIndex)
            : base(text, imageIndex)
        {
            Initialize();
        }


        /// <summary>
        /// Initializes a new instance of the ActiveRow class with an array of strings representing subitems and 
        /// the image index position of the item's icon. 
        /// </summary>
        /// <param name="items">An array of strings that represent the subitems of the new item.</param>
        /// <param name="imageIndex">The zero-based index of the image within the ImageList associated with the ListView that contains the item.</param>
        public ActiveRow(string[] items, int imageIndex)
            : base(items, imageIndex)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the image index position of the 
        /// item's icon; the foreground color, background color, and font of the item; and an array 
        /// of strings representing subitems.
        /// </summary>
        /// <param name="items">An array of strings that represent the subitems of the new item.</param>
        /// <param name="imageIndex">The zero-based index of the image within the ImageList associated with the ListView that contains the item.</param>
        /// <param name="foreColor">A Color that represents the foreground color of the item.</param>
        /// <param name="backColor">A Color that represents the background color of the item.</param>
        /// <param name="font">A Font that represents the font to display the item's text in.</param>
        public ActiveRow(string[] items, int imageIndex, Color foreColor, Color backColor, Font font)
            : base(items, imageIndex, foreColor, backColor, font)
        {
            Initialize();
        }

        #endregion

        #region --- New Constructors ------------------------------

        /// <summary>
        /// Initializes a new instance of the ActiveRow class and assigns it to the specified group.
        /// </summary>
        /// <param name="group">The ListViewGroup to assign the item to.</param>
        public ActiveRow(ListViewGroup group)
            : base(group)
        {
            Initialize();
        }


        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the specified subitems and image. 
        /// </summary>
        /// <param name="subItems">An array of ListViewItem.ListViewSubItem objects.</param>
        /// <param name="imageKey">The name of the image within the ImageList of the owning ListView to display in the ListViewItem.</param>
        public ActiveRow(ActiveCell[] subItems, string imageKey)
            : base(subItems, imageKey)
        {
            Initialize();
        }


        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the specified serialization information and streaming context.
        /// </summary>
        /// <param name="info">A SerializationInfo containing information about the ListViewItem to be initialized.</param>
        /// <param name="context">A StreamingContext that indicates the source destination and context information of a serialized stream.</param>
        public ActiveRow(SerializationInfo info, StreamingContext context)
            : base(info, context)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the specified key, item text and the image index position of the item's icon.
        /// </summary>
        /// <param name="key">The name of the item used as a search key</param>
        /// <param name="text">The text to display for the item</param>
        /// <param name="imageIndex">The zero-based index of the image within the ImageList associated with the ListView that contains the item.</param>
        public ActiveRow(string key, string text, int imageIndex)
            : base(text, imageIndex)
        {
            base.Name = key;
            Initialize();

        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the specified key, item text and the image.
        /// </summary>
        /// <param name="key">The name of the item used as a search key</param>
        /// <param name="text">The text to display for the item</param>
        /// <param name="imageKey">The name of the image within the ImageList of the owning Grid to display in the ListViewItem.</param>
        public ActiveRow(string key, string text, string imageKey)
            : base(text, imageKey)
        {
            base.Name = key;
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the specified item text and assigns it to the specified group
        /// </summary>
        /// <param name="text">The text to display for the item.</param>
        /// <param name="group">The ListViewGroup to assign the item to</param>
        public ActiveRow(string text, ListViewGroup group)
            : base(text, group)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the specified text and image. 
        /// </summary>
        /// <param name="text">The text to display for the item.</param>
        /// <param name="imageKey">The name of the image within the ImageList of the owning ListView to display in the ListViewItem.</param>
        public ActiveRow(string text, string imageKey)
            : base(text, imageKey)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with an array of strings representing subitems, and assigns the item to the specified group. 
        /// </summary>
        /// <param name="items">An array of strings that represent the subitems of the new item.</param>
        /// <param name="group">The ListViewGroup to assign the item to.</param>
        public ActiveRow(string[] items, ListViewGroup group)
            : base(items, group)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the specified item and subitem text and image. 
        /// </summary>
        /// <param name="items">An array containing the text of the subitems of the ListViewItem.</param>
        /// <param name="imageKey">The name of the image within the ImageList of the owning ListView to display in the ListViewItem.</param>
        public ActiveRow(string[] items, string imageKey)
            : base(items, imageKey)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the image index position of the item's icon and an array of ListViewItem.ListViewSubItem objects, and assigns the item to the specified group.
        /// </summary>
        /// <param name="subItems">An array of type ListViewItem.ListViewSubItem that represents the subitems of the item.</param>
        /// <param name="imageIndex">The zero-based index of the image within the ImageList associated with the ListView that contains the item</param>
        /// <param name="group">The ListViewGroup to assign the item to.</param>
        public ActiveRow(ActiveCell[] subItems, int imageIndex, ListViewGroup group)
            : base(subItems, imageIndex, group)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the specified subitems, image, and group.
        /// </summary>
        /// <param name="subItems">An array of ListViewItem.ListViewSubItem objects that represent the subitems of the ListViewItem.</param>
        /// <param name="imageKey">The name of the image within the ImageList of the owning ListView to display in the item.</param>
        /// <param name="group">The ListViewGroup to assign the item to.</param>
        public ActiveRow(ActiveCell[] subItems, string imageKey, ListViewGroup group)
            : base(subItems, imageKey, group)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the specified item text and the image index position of the item's icon, and assigns the item to the specified group. 
        /// </summary>
        /// <param name="text">The text to display for the item.</param>
        /// <param name="imageIndex">The zero-based index of the image within the ImageList associated with the ListView that contains the item. </param>
        /// <param name="group">The ListViewGroup to assign the item to.</param>
        public ActiveRow(string text, int imageIndex, ListViewGroup group)
            : base(text, imageIndex, group)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the specified text, image, and group.
        /// </summary>
        /// <param name="text">The text to display for the item.</param>
        /// <param name="imageKey">The name of the image within the ImageList of the owning ListView to display in the item.</param>
        /// <param name="group">The ListViewGroup to assign the item to.</param>
        public ActiveRow(string text, string imageKey, ListViewGroup group)
            : base(text, imageKey, group)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the image index position of the item's icon and an array of strings representing subitems, and assigns the item to the specified group.
        /// </summary>
        /// <param name="items">An array of strings that represent the subitems of the new item</param>
        /// <param name="imageIndex">The zero-based index of the image within the ImageList associated with the ListView that contains the item. </param>
        /// <param name="group">The ListViewGroup to assign the item to.</param>
        public ActiveRow(string[] items, int imageIndex, ListViewGroup group)
            : base(items, imageIndex, group)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with subitems containing the specified text, image, and group.
        /// </summary>
        /// <param name="items">An array of strings that represents the text for subitems of the ListViewItem.</param>
        /// <param name="imageKey">The name of the image within the ImageList of the owning ListView to display in the item.</param>
        /// <param name="group">The ListViewGroup to assign the item to.</param>
        public ActiveRow(string[] items, string imageKey, ListViewGroup group)
            : base(items, imageKey, group)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the subitems containing the specified text, image, colors, and font. 
        /// </summary>
        /// <param name="items">An array of strings that represent the text of the subitems for the ListViewItem.</param>
        /// <param name="imageKey">The name of the image within the ImageList of the owning ListView to display in the item</param>
        /// <param name="foreColor">A Color that represents the foreground color of the item</param>
        /// <param name="backColor">A Color that represents the background color of the item</param>
        /// <param name="font">A Font to apply to the item text</param>
        public ActiveRow(string[] items, string imageKey, Color foreColor, Color backColor, Font font)
            : base(items, imageKey, foreColor, backColor, font)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the image index position of the 
        /// item's icon; the foreground color, background color, and font of the item; and an array of 
        /// strings representing subitems. Assigns the item to the specified group. 
        /// </summary>
        /// <param name="items">An array of strings that represent the subitems of the new item</param>
        /// <param name="imageIndex">The zero-based index of the image within the ImageList associated with the ListView that contains the item</param>
        /// <param name="foreColor">A Color that represents the foreground color of the item</param>
        /// <param name="backColor">A Color that represents the background color of the item</param>
        /// <param name="font">A Font that represents the font to display the item's text in</param>
        /// <param name="group">The ListViewGroup to assign the item to</param>
        public ActiveRow(string[] items, int imageIndex, Color foreColor, Color backColor, Font font, ListViewGroup group)
            : base(items, imageIndex, foreColor, backColor, font, group)
        {
            Initialize();
        }

        /// <summary>
        /// Initializes a new instance of the ActiveRow class with the subitems containing the specified 
        /// text, image, colors, font, and group. 
        /// </summary>
        /// <param name="items">An array of strings that represents the text of the subitems for the ListViewItem</param>
        /// <param name="imageKey">The name of the image within the ImageList of the owning ListView to display in the item</param>
        /// <param name="foreColor">A Color that represents the foreground color of the item</param>
        /// <param name="backColor">A Color that represents the background color of the item</param>
        /// <param name="font">A Font to apply to the item text</param>
        /// <param name="group">The ListViewGroup to assign the item to</param>
        public ActiveRow(string[] items, string imageKey, Color foreColor, Color backColor, Font font, ListViewGroup group)
            : base(items, imageKey, foreColor, backColor, font, group)
        {
            Initialize();
        }

        #endregion

        #region --- Public Methods --------------------------------

        /// <summary>
        /// Invalidates the whole area of the row and causes it to be redrawn
        /// </summary>
        public void Invalidate()
        {
            if (this.Grid != null)
                this.Grid.Invalidate(this.Bounds);
        }

        /// <summary>
        /// Invalidates a specific area of the row and causes it to be redrawn
        /// </summary>
        public void Invalidate(Rectangle rc)
        {
            if (this.Grid != null)
                this.Grid.Invalidate(rc);
        }

        /// <summary>
        /// Paints the row
        /// </summary>
        /// <param name="g"></param>
        /// <param name="highlighted"></param>
        public void Draw(DrawListViewItemEventArgs e)
        {
            // Is the row Highlighted?
            this.Selected = ((e.State & ListViewItemStates.Selected) != 0);

            Draw(e.Graphics, e.ItemIndex);
        }

        public void OnMouseMove(MouseEventArgs e)
        {
            if (this._linkLabel != null)
            {
                this.Grid.Cursor = this._linkLabel.MouseOver(e.Location) ? Cursors.Hand : Cursors.Default;

                if (this._linkLabel.Changed)
                    Draw(this.Grid.CreateGraphics(), this.Index);
            }
        }

        public bool OnMouseClick(MouseEventArgs e)
        {
            return (this._linkLabel==null ? false : this._linkLabel.OnMouseClick(e));
        }


        public override string ToString()
        {
            return "LVRow{}";
        }

        #endregion

        #region --- Private Methods -------------------------------

        /// <summary>
        /// Gets a rectangle representing the Pre-Cell area of the row.
        /// </summary>
        /// <returns>Rectangle representing the Pre-Cell area of the row</returns>
        private Rectangle PreCellBounds()
        {
            Rectangle labelBounds = this.GetBounds(ItemBoundsPortion.Label);
            return new Rectangle(0, this.Bounds.Y, labelBounds.X + labelBounds.Width, this.Bounds.Height - (this.Grid.GridLines ? 1 : 0));
        }

        private Rectangle PostCellBounds()
        {
            // Calculate the total width of all columns in the row.
            int totalHeaderWidth = 0;
            foreach (ActiveColumnHeader column in this.Grid.Columns)
                totalHeaderWidth += column.Width;

            // Create a rectangle representing the post-cell area of the row.
            return new Rectangle(totalHeaderWidth + this.Bounds.X + (this.Grid.GridLines ? 1 : 0), this.Bounds.Y, this.Grid.Width - totalHeaderWidth, this.Bounds.Height - (this.Grid.GridLines ? 1 : 0));
        }

        /// <summary>
        /// Initializes the class data.
        /// </summary>
        private void Initialize()
        {
            this._cells = new ActiveCellCollection(this);
            this._linkLabel = new LinkLabelCell(this.Bounds);

            this._linkLabel.OnLeftMouseClick += new LinkLabelCell.OnLeftMouseClickHandler(_linkLabel_OnLeftMouseClick);
            this._linkLabel.OnRightMouseClick += new LinkLabelCell.OnRightMouseClickHandler(_linkLabel_OnRightMouseClick);
        }

        private void _linkLabel_OnRightMouseClick(object sender, EventArgs e)
        {
            if(this.Grid != null)
              this.Grid.RowHeaderRightClick(this);
        }

        private void _linkLabel_OnLeftMouseClick(object sender, EventArgs e)
        {
            if(this.Grid != null)
              this.Grid.RowHeaderLeftClick(this);
        }


        private void Draw(Graphics g, int ItemIndex)
        {
            if (this.Grid != null)
            {
                // This bit needs some explanation....
                // Each row can be thought of as divided into three sections:
                // Section 1: The bit before the cells [PreCell]
                // Section 2: The cells
                // Section 3: The bit after the cells [PostCell]
                // In order to prevent any flickering of the cell content due to unnecessarly
                // invalidating the cells we need to handle each of the sections seperately.

                // Create a rectangle representing the pre-cell area of the row.
                Rectangle rcPre = PreCellBounds();

                // Create a rectangle representing the post-cell area of the row.
                Rectangle rcPost = PostCellBounds();

                if (this.Grid.UseGradient && AlternateRow )
                {
                    DrawAlternatingGradient(g, rcPre, rcPost);
                }
                else
                {
                    DrawPlain(g, ItemIndex, rcPre, rcPost);
                }


                // Invalidate the post-cell region
                // TODO: XP-Bug
                // Warning! This presents a problem in Windows-XP as it causes the mouse cursor
                // to flicker when it is positioned over this area. It also sends the processor
                // into overdrive. 
                //
                // if (this.Selected)
                //    this.Grid.Invalidate(rcPost);


                // Draw the row foreground
                DrawForeground(g);
            }
        }

        private void DrawPlain(Graphics g, int ItemIndex, Rectangle rcPre, Rectangle rcPost)
        {
            g.FillRectangle((this.Selected ? SystemBrushes.Highlight : (AlternateRow ? ActiveGrid.Paintbox.AlternateBackgroundBrush : ActiveGrid.Paintbox.NormalBackgroundBrush)), rcPre);

            // TODO: XP-Bug
            // g.FillRectangle((this.Selected ? SystemBrushes.Highlight : (AlternateRow ? ActiveGrid.Paintbox.AlternateBackgroundBrush : ActiveGrid.Paintbox.NormalBackgroundBrush)), rcPost);

        }

        private void DrawAlternatingGradient(Graphics g, Rectangle rcPre, Rectangle rcPost)
        {
            using (LinearGradientBrush bg = new LinearGradientBrush(rcPre, this.Grid.AlternatingGradientStartColor, this.Grid.AlternatingGradientEndColor, LinearGradientMode.Vertical))
            {
                g.FillRectangle((this.Selected ? SystemBrushes.Highlight : bg), rcPre);
            }

            // TODO: XP-Bug
            // using (LinearGradientBrush bg = new LinearGradientBrush(rcPost, this.Grid.AlternatingGradientStartColor, this.Grid.AlternatingGradientEndColor, LinearGradientMode.Vertical))
            // {
            //    g.FillRectangle((this.Selected ? SystemBrushes.Highlight : bg), rcPost);
            // }
 
        }

        /// <summary>
        /// Draws the row header text
        /// </summary>
        /// <param name="g"></param>
        /// <param name="highlighted"></param>
        private void DrawForeground(Graphics g)
        {
            using (StringFormat sf = new StringFormat())
            {
                // Fetch the column header of the row label.
                ActiveColumnHeader header = this.Grid.Columns[0];
                if (header != null)
                {
                    // Set the user-defined string format.
                    sf.Alignment = header.CellHorizontalAlignment;
                    sf.LineAlignment = header.CellVerticalAlignment;
                    sf.Trimming = StringTrimming.EllipsisCharacter;
                    sf.FormatFlags = StringFormatFlags.NoWrap;
                }

                // Draw the contents of the row label.
                if (this.Selected)
                {
                    g.DrawString(this.Text, this.Font, SystemBrushes.HighlightText, this.GetBounds(ItemBoundsPortion.Label), sf);
                }
                else
                {
                    // Are we using LinkLabel-style headers for the rows?
                    if (this.Grid.UseRowHeaderButtons)
                    {
                        this._linkLabel.Draw(g, this.Text, this.Font, this.GetBounds(ItemBoundsPortion.Label), sf, this.Selected);
                    }
                    else
                    {
                        g.DrawString(this.Text, this.Font, ActiveGrid.Paintbox.Brush(this.ForeColor), this.GetBounds(ItemBoundsPortion.Label), sf);
                    }
                }
            }
        }

        #endregion

        #region --- Properties ------------------------------------

        /// <summary>
        /// Gets the background color of the item's text
        /// </summary>
        public new Color BackColor
        {
            get { return AlternateRow ? ActiveGrid.Paintbox.AlternateBackgroundColor : ActiveGrid.Paintbox.NormalBackgroundColor; }
        }

        public new Rectangle Bounds
        {
            get { return new Rectangle(base.Bounds.X, base.Bounds.Y, 230, base.Bounds.Height);  }
        }


        /// <summary>
        /// Gets a flag to indicate if the row is an alternate row. 
        /// </summary>
        public Boolean AlternateRow
        {
            get
            {
                bool alternate = false;

                if (this.Grid != null && this.Grid.UseAlternateRowColors)
                    alternate = (this.Index % 2 == 1);

                return alternate;
            }
        }

        /// <summary>
        /// Gets a collection containing all cells of the row
        /// </summary>
        [Category("Data"),
        DefaultValue(null),
        Description("The ActiveCell items contained in the ActiveRow"),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public new ActiveCellCollection SubItems
        {
            get { return this._cells; }
        }

        /// <summary>
        /// Gets the ActiveGrid control that contains the row
        /// </summary>
        [Browsable(false)]
        public ActiveGrid Grid
        {
            get { return base.ListView as ActiveGrid; }
        }

        /// <summary>
        /// Gets the zero-based index of the cell within the row
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public ActiveCell this[int index]
        {
            get
            {
                if (index >= 0 && index < base.SubItems.Count)
                    return base.SubItems[index] as ActiveCell;
                else
                    throw (new IndexOutOfRangeException(String.Format("The cell index [{0}] is out of range", index)));
            }
        }

        #endregion

        #region --- Nested Class ActiveCellCollection -------------

        /// <summary>
        /// Represents a collection of ActiveRow.ActiveCell objects stored in an ActiveRow.
        /// </summary>
        public class ActiveCellCollection : ListViewItem.ListViewSubItemCollection
        {
            #region --- Public Constructors ------------------------

            /// <summary>
            /// Initializes a new instance of the ActiveRow.ActiveCellCollection class
            /// </summary>
            /// <param name="owner">The ActiveRow that owns the collection</param>
            public ActiveCellCollection(ActiveRow owner)
                : base(owner)
            {
            }

            #endregion

            #region --- Public Methods -----------------------------

            /// <summary>
            /// Adds an existing ActiveRow.ActiveCell to the collection
            /// </summary>
            /// <param name="item">The ActiveRow.ActiveCell to add to the collection</param>
            /// <returns>The ActiveRow.ActiveCell that was added to the collection</returns>
            public ActiveCell Add(ActiveCell item)
            {
                return base.Add(item) as ActiveCell;
            }


            /// <summary>
            /// Adds a cell to the collection with specified text. 
            /// </summary>
            /// <param name="text">The text to display for the subitem</param>
            /// <returns>The ActiveRow.ActiveCell that was added to the collection</returns>
            public new ActiveCell Add(string text)
            {
                return base.Add(text) as ActiveCell;
            }

            /// <summary>
            /// Adds a cell to the collection with specified text, foreground color, background color, and font settings
            /// </summary>
            /// <param name="text">The text to display for the subitem</param>
            /// <param name="foreColor">A Color that represents the foreground color of the subitem</param>
            /// <param name="backColor">A Color that represents the background color of the subitem.</param>
            /// <param name="font">A Font that represents the typeface to display the subitem's text in</param>
            /// <returns>The ActiveRow.ActiveCell that was added to the collection</returns>
            public new ActiveCell Add(string text, Color foreColor, Color backColor, Font font)
            {
                return base.Add(text, foreColor, backColor, font) as ActiveCell;
            }

            /// <summary>
            /// Adds an array of ActiveRow.ActiveCell objects to the collection
            /// </summary>
            /// <param name="items">An array of ActiveRow.ActiveCell objects to add to the collection</param>
            public void AddRange(ActiveCell[] items)
            {
                base.AddRange(items);
            }

            /// <summary>
            /// Determines whether the specified cell is located in the collection
            /// </summary>
            /// <param name="subItem">An ActiveRow.ActiveCell representing the subitem to locate in the collection</param>
            /// <returns>true if the cell is contained in the collection; otherwise, false</returns>
            public bool Contains(ActiveCell subItem)
            {
                return base.Contains(subItem);
            }

            #endregion

            #region --- Public Properties --------------------------

            /// <summary>
            /// Gets or sets the cell at the specified index within the collection.
            /// </summary>
            /// <param name="index">The index of the cell in the collection to get or set</param>
            public new ActiveCell this[int index]
            {
                get { return base[index] as ActiveCell; }
                set { base[index] = value; }
            }

            /// <summary>
            /// Retrieves the cell with the specified key.
            /// </summary>
            /// <param name="index">The name of the cell to retrieve.</param>
            public new ActiveCell this[string key]
            {
                get { return base[key] as ActiveCell; }
            }

            #endregion
        }

        #endregion

        #region --- Nested Class Active Cell ----------------------

        /// <summary>
        /// Class representing the default cell of an ActiveRow.
        /// </summary>
        public class ActiveCell : ListViewItem.ListViewSubItem
        {
            #region --- Class Data ------------------------------------

            private readonly String DEFAULT_FORMAT_SPECIFIER = "{0}";
            public static Int32 DEFAULT_FLASH_DURATION = 2000;
            /// <summary>
            /// The row to which the cell belongs.
            /// </summary>
            private ActiveRow _row = null;
            /// <summary>
            /// The column to which the cell belongs.
            /// </summary>
            private ActiveColumnHeader _column = null;
            /// <summary>
            /// Synchronization object
            /// </summary>
            private Object synchRoot = new object();
            /// <summary>
            /// The current style enumeration of the cell
            /// </summary>
            private CellStyle _style;
            /// <summary>
            /// The decimal value associated with the cell
            /// </summary>
            private Decimal _decValue = Decimal.Zero;
            /// <summary>
            /// Indicates whether the contents of the cell are displaying a decimal value
            /// </summary>
            private bool _useDecimal = false;
            /// <summary>
            /// Reference to the callback method for the background timer.
            /// </summary>
            private System.Threading.TimerCallback callback;
            /// <summary>
            /// Enumeration for the current state of the cell.
            /// </summary>
            private volatile CellState _state;
            /// <summary>
            /// Indicates whether the cell is currently in a flashed state.
            /// </summary>
            private volatile bool _isFlashed = false;
            /// <summary>
            /// Handle the fading functionality of the cell.
            /// </summary>
            private ActiveCellFader _fader = new ActiveCellFader();
            /// <summary>
            /// The current number of itearations into a fade.
            /// </summary>
            private int _iterations;
            /// <summary>
            /// Indicates that the cell has been drawn at least once.
            /// </summary>
            private bool _firstTime = true;

            #region --- Fonts -----------------------------

            /// <summary>
            /// Font to use for the pre text
            /// </summary>
            private Font fldPreTextFont;
            /// <summary>
            /// Font to use for the post text
            /// </summary>
            private Font fldPostTextFont;
            /// <summary>
            /// Font used when the cell is in the flashed state
            /// </summary>
            private Font fldFlashFont;

            #endregion

            #region --- Colours ---------------------------

            /// <summary>
            /// Foreground color for the pre-text
            /// </summary>
            private Color fldPreTextForeColor;
            /// <summary>
            /// Foreground color for the post-text
            /// </summary>
            private Color fldPostTextForeColor;
            /// <summary>
            /// A color representing the starting color for the gradient
            /// </summary>
            private Color fldGradientStartColor;
            /// <summary>
            /// A color representing the ending color for the gradient
            /// </summary>
            private Color fldGradientEndColor;
            /// <summary>
            /// Background colour while cell is being flashed
            /// </summary>
            private Color fldFlashBackColor;
            /// <summary>
            /// Foreground color while the cell is being flashed
            /// </summary>
            private Color fldFlashForeColor;
            /// <summary>
            /// Foreground color for the pre-text while the cell is being flashed
            /// </summary>
            private Color fldFlashPreTextForeColor;
            /// <summary>
            /// Foreground color for the post-text while the cell is being flashed
            /// </summary>
            private Color fldFlashPostTextForeColor;
            /// <summary>
            /// A color representing the starting color for the gradient when the cell is flashed
            /// </summary>
            private Color fldFlashGradientStartColor;
            /// <summary>
            /// A color representing the ending color for the gradient when the cell is flashed
            /// </summary>
            private Color fldFlashGradientEndColor;

            #endregion

            #region --- Strings ---------------------------

            /// <summary>
            /// Text that is to appear at the near left of the cell
            /// </summary>
            private String fldPreText;
            /// <summary>
            /// Text that is to appear at the far right of the cell
            /// </summary>
            private String fldPostText;
            /// <summary>
            /// Text that is to appear at the near left of the cell when it is in the flashed state
            /// </summary>
            private String fldFlashPreText;
            /// <summary>
            /// Text that is to appear at the far right of the cell when it is in the flashed state
            /// </summary>
            private String fldFlashPostText;
            /// <summary>
            /// A String containing zero or more format items for the main text within the cell 
            /// </summary>
            private String fldFormat;

            #endregion

            #region --- Miscellaneous ---------------------

            /// <summary>
            /// Vertical alignment of the main text
            /// </summary>
            private StringAlignment fldVerticalAlignment;
            /// <summary>
            /// Horizontal alignment of the main text
            /// </summary>
            private StringAlignment fldHorizontalAlignment;
            /// <summary>
            /// Enumeration specifying the orientation of the gradient when in a flashed state
            /// </summary>
            private LinearGradientMode fldFlashLinearGradientMode;
            /// <summary>
            /// Flag to indicate that a different fore-color should be used for negative values
            /// </summary>
            private bool fldUseNegativeForeColor;
            /// <summary>
            /// Flag to indicate whether zero-values will be displayed or not.
            /// </summary>
            private bool fldDisplayZeroValues = false;

            #endregion

            #endregion

            #region --- Public Constructors ---------------------------

            /// <summary>
            /// Initializes a new instance of the ActiveCell class with default values
            /// </summary>
            public ActiveCell()
                : base()
            {
                Initialize();
            }

            /// <summary>
            /// Initializes a new instance of the ActiveCell class with the specified owner and text
            /// </summary>
            /// <param name="owner">A LVRow that represents the item that owns the subitem</param>
            /// <param name="text">The text to display for the subitem</param>
            public ActiveCell(ActiveRow owner, string text)
                : base(owner, text)
            {
                this._row = owner;

                Initialize();
            }

            /// <summary>
            /// Initializes a new instance of the ActiveCell class with 
            /// the specified owner, text, foreground color, background color, and font values. 
            /// </summary>
            /// <param name="owner">A LVRow that represents the item that owns the subitem</param>
            /// <param name="text">The text to display for the subitem</param>
            /// <param name="foreColor">A Color that represents the foreground color of the subitem</param>
            /// <param name="backColor">A Color that represents the background color of the subitem</param>
            /// <param name="font">A Font that represents the font to display the subitem's text in</param>
            public ActiveCell(ActiveRow owner, string text, Color foreColor, Color backColor, Font font)
                : base(owner, text, foreColor, backColor, font)
            {
                this._row = owner;

                Initialize();
            }

            /// <summary>
            /// Set the default values for all of the class data.
            /// </summary>
            private void Initialize()
            {
                // Set the timer callback method.
                callback = flashTimerTimeout;

                this._iterations = 0;

                // FONTS
                this.fldPreTextFont = base.Font;
                this.fldPostTextFont = base.Font;
                this.fldFlashFont = base.Font;

                // COLORS
                this.fldPreTextForeColor = ActiveGrid.Paintbox.PreTextColor;
                this.fldPostTextForeColor = ActiveGrid.Paintbox.PostTextColor;
                this.fldFlashForeColor = ActiveGrid.Paintbox.FlashForeColor;
                this.fldFlashBackColor = ActiveGrid.Paintbox.FlashBackgroundColor;
                this.fldFlashGradientStartColor = ActiveGrid.Paintbox.FlashGradientStartColor;
                this.fldFlashGradientEndColor = ActiveGrid.Paintbox.FlashGradientEndColor;
                this.fldFlashPreTextForeColor = ActiveGrid.Paintbox.FlashPreTextColor;
                this.fldFlashPostTextForeColor = ActiveGrid.Paintbox.FlashPostTextColor;

                // STRINGS
                this.fldPreText = String.Empty;
                this.fldPostText = String.Empty;
                this.fldFlashPreText = String.Empty;
                this.fldFlashPostText = String.Empty;
                this.fldFormat = DEFAULT_FORMAT_SPECIFIER;

                // MISCELLENEOUS
                this.fldVerticalAlignment = StringAlignment.Center;
                this.fldHorizontalAlignment = StringAlignment.Center;
                this.fldFlashLinearGradientMode = LinearGradientMode.Vertical;
                this.fldDisplayZeroValues = false;
                this.fldUseNegativeForeColor = false;
                this._state = CellState.Normal;
                this._style = CellStyle.Plain;
            }

            #endregion

            #region --- Public Methods --------------------------------

            /// <summary>
            /// Invalidates the entire surface of the cell and causes it to be redrawn
            /// N.B This method is not thread-safe.
            /// </summary>
            public void Invalidate()
            {
                if (this._row != null)
                    this._row.Invalidate(this.Bounds);
            }

            /// <summary>
            /// Invalidates the entire surface of the cell and causes it to be redrawn in
            /// a thread-safe manner.
            /// N.B. This request may originate from a different thread than the one
            ///      from which it originated. In the interest of thread-safety, we'll
            ///      ask the parent control to del with it accordingly.
            ///      (A reference to the whole cell is sent because any attempt to get
            ///      the Bounds will not be safe).
            /// </summary>
            public void InvalidateCell()
            {
                if (this._row != null && this._row.Grid != null)
                    this._row.Grid.InvalidateCell(this);
            }

            /// <summary>
            /// Paints the cell.
            /// </summary>
            /// <param name="g"></param>
            /// <param name="highlighted"></param>
            public void Draw(Graphics g, bool selected)
            {
                this.CellState = selected ? CellState.Highlighted : (this._isFlashed ? CellState.Flashed : CellState.Normal);

                Draw(g);
            }

            /// <summary>
            /// Paints the cell.
            /// </summary>
            /// <param name="g"></param>
            public void Draw(Graphics g)
            {
                SetDrawingOptions();

                DrawBackground(g);

                DrawForeground(g);
            }

            /// <summary>
            /// Changes the state of the cell into 'Flashed' mode
            /// </summary>
            public void Flash()
            {
                // Only ever flash the cell if the parent grid supports it and the layout
                // logic is not currently suspended.
                if (this._row.Grid.AllowFlashing && !this._row.Grid.LayoutSuspended)
                {
                    // Set the iteration level.
                    Interlocked.Exchange(ref this._iterations, this._row.Grid.UseFlashFadeOut ? ActiveCellFader.DEFAULT_TOTAL_ITERATIONS : 0);

                    // Is the cell already 'Flashed'?
                    if (!this._isFlashed || this._row.Grid.UseFlashFadeOut)
                        StartBackgroundTimer();
                }

                // Redraw the cell.
                Draw(this._row.Grid.CreateGraphics());
            }


            public override string ToString()
            {
                return "ActiveCell{}";
            }

            #endregion

            #region --- Private Methods -------------------------------

            /// <summary>
            /// Sets the initial drawing specifications of the cell prior to drawing for the first time.
            /// This only need to be called once when it is first drawn.
            /// </summary>
            private void SetDrawingOptions()
            {
                if (this._row != null && this._row.Grid != null && this._firstTime)
                {
                    // Set the Column-level drawing options for the cell.
                    // The values are defined in the Column Header object to which this cell belongs.
                    this._column = this._row.Grid.Columns[this._row.SubItems.IndexOf(this)];
                    if (this._column != null)
                    {
                        this.fldHorizontalAlignment = this._column.CellHorizontalAlignment;
                        this.fldVerticalAlignment = this._column.CellVerticalAlignment;
                        this.Format = this._column.CellFormat;
                        this.fldDisplayZeroValues = this._column.DisplayZeroValues;
                    }

                    // Set Grid-level drawing options for the cell.
                    // The values are defined in the Grid object to which this cell belongs.
                    if (this._isFlashed)
                        this._style = this._row.Grid.UseFlashGradient ? CellStyle.Gradient : CellStyle.Plain;
                    else
                        this._style = this._row.Grid.UseGradient ? CellStyle.Gradient : CellStyle.Plain;

                    // Set the Grid-level Flash settings.
                    this.fldFlashForeColor = ActiveGrid.Paintbox.FlashForeColor;
                    this.fldFlashBackColor = ActiveGrid.Paintbox.FlashBackgroundColor;
                    this.fldFlashGradientStartColor = ActiveGrid.Paintbox.FlashGradientStartColor;
                    this.fldFlashGradientEndColor = ActiveGrid.Paintbox.FlashGradientEndColor;
                    this.fldFlashLinearGradientMode = ActiveGrid.Paintbox.FlashLinearGradientMode;

                    // Set the background colour, taking into account the fact that the grid
                    // may be using an alternating background.
                    this.BackColor = this._row.AlternateRow ? ActiveGrid.Paintbox.AlternateBackgroundColor : ActiveGrid.Paintbox.NormalBackgroundColor;
                    this._fader.StartColor = ActiveGrid.Paintbox.FlashBackgroundColor;
                    this._fader.EndColor = this.BackColor;
                    this._fader.TotalIterations = ActiveCellFader.DEFAULT_TOTAL_ITERATIONS;

                    this._firstTime = false;
                }
            }

            /// <summary>
            /// Draws the background of the cell taking into account the current state.
            /// </summary>
            /// <param name="g"></param>
            private void DrawBackground(Graphics g)
            {
                // Set Grid-level drawing options for the cell.
                // The values are defined in the Grid object to which this cell belongs.
                if (this._isFlashed)
                    this._style = this._row.Grid.UseFlashGradient ? CellStyle.Gradient : CellStyle.Plain;
                else
                    this._style = this._row.Grid.UseGradient ? CellStyle.Gradient : CellStyle.Plain;

                switch (this._state)
                {
                    case CellState.Highlighted:
                        DrawHighlighted(g);
                        break;
                    case CellState.Flashed:
                        if (this._style == CellStyle.Gradient)
                            DrawGradient(g);
                        else
                            DrawPlain(g);
                        break;
                    default:
                        if (this._style == CellStyle.Gradient && this._row.AlternateRow)
                            DrawGradient(g);
                        else
                            DrawPlain(g);
                        break;
                }
            }

            /// <summary>
            /// Gets the bounding rectangle of the cell taking into account the grid lines.
            /// </summary>
            /// <returns></returns>
            private Rectangle CellBounds()
            {
                return new Rectangle(this.Bounds.X + (this._row.Grid.GridLines ? 1 : 0), this.Bounds.Y, this.Bounds.Width - (this._row.Grid.GridLines ? 1 : 0), this.Bounds.Height - (this._row.Grid.GridLines ? 1 : 0));
            }

            /// <summary>
            /// Set the current cell state to 'Flashed'
            /// </summary>
            private void FlashOn()
            {
                if (!this._isFlashed)
                {
                    if (this._row != null && this._row.Grid != null)
                        this._row.Grid.IncrementFlashCount();

                    this._isFlashed = true;

                    if (this.CellState != CellState.Highlighted)
                        this.CellState = CellState.Flashed;
                }
            }

            /// <summary>
            /// Set the current cell state to 'Not-Flashed'
            /// </summary>
            private void FlashOff()
            {
                if (this._isFlashed)
                {
                    this._isFlashed = false;

                    if (this._row != null && this._row.Grid != null)
                        this._row.Grid.DecrementFlashCount();

                    if (this.CellState != CellState.Highlighted)
                        this.CellState = CellState.Normal;
                }
            }

            #endregion

            #region --- Drawing Methods -------------------------------

            /// <summary>
            /// Draws the foreground of the cell taking into account the current state.
            /// </summary>
            /// <param name="g"></param>
            private void DrawForeground(Graphics g)
            {
                // Discover which of the three text areas we need to draw and which we can ignore.
                // This will prevent any unnecessary drawing from taking place and will boost performance.
                bool drawText = !String.IsNullOrEmpty(this.Text);
                bool drawPreText = (this._isFlashed) ? !String.IsNullOrEmpty(this.fldFlashPreText) : !String.IsNullOrEmpty(this.fldPreText);
                bool drawPostText = (this._isFlashed) ? !String.IsNullOrEmpty(this.fldFlashPostText) : !String.IsNullOrEmpty(this.fldPostText);

                // If there's nothing to draw then return.
                if (!drawText && !drawPreText && !drawPostText)
                    return;


                // Set the correct brushes to use when drawing each of the three text areas.
                // The choice of brush will be based mainly on the current state of the cell.
                Brush fgTextBrush = null;
                Brush fgPreTextBrush = null;
                Brush fgPostTextBrush = null;

                switch (this._state)
                {
                    case CellState.Highlighted:
                        if (drawText) fgTextBrush = SystemBrushes.HighlightText;
                        if (drawPreText) fgPreTextBrush = SystemBrushes.HighlightText;
                        if (drawPostText) fgPostTextBrush = SystemBrushes.HighlightText;
                        break;
                    case CellState.Flashed:
                        if (drawText) fgTextBrush = this.fldUseNegativeForeColor ? ActiveGrid.Paintbox.NegativeValueBrush : ActiveGrid.Paintbox.Brush(this.fldFlashForeColor);
                        if (drawPreText) fgPreTextBrush = ActiveGrid.Paintbox.Brush(this.fldFlashPreTextForeColor);
                        if (drawPostText) fgPostTextBrush = ActiveGrid.Paintbox.Brush(this.fldFlashPostTextForeColor);
                        break;
                    case CellState.Normal:
                    default:
                        if (drawText) fgTextBrush = this.fldUseNegativeForeColor ? ActiveGrid.Paintbox.NegativeValueBrush : ActiveGrid.Paintbox.Brush(base.ForeColor);
                        if (drawPreText) fgPreTextBrush = ActiveGrid.Paintbox.Brush(this.fldPreTextForeColor);
                        if (drawPostText) fgPostTextBrush = ActiveGrid.Paintbox.Brush(this.fldPostTextForeColor);
                        break;
                }

                // Draw the text contents of the cell.
                using (StringFormat sf = new StringFormat())
                {
                    sf.LineAlignment = this.fldVerticalAlignment;

                    // Draw the Pre-Text (if there is any)
                    SizeF szPreText = SizeF.Empty;
                    if (drawPreText)
                    {
                        sf.Alignment = StringAlignment.Near;
                        sf.Trimming = StringTrimming.Character;
                        sf.FormatFlags = StringFormatFlags.NoWrap;
                        szPreText = g.MeasureString((this._state == CellState.Flashed) ? this.fldFlashPreText : this.fldPreText, this.fldPreTextFont);
                        g.DrawString((this._state == CellState.Flashed) ? this.fldFlashPreText : this.fldPreText, this.fldPreTextFont, fgPreTextBrush, this.Bounds, sf);
                    }

                    // Draw the Post-Text (if there is any)
                    SizeF szPostText = SizeF.Empty;
                    if (drawPostText)
                    {
                        sf.Alignment = StringAlignment.Far;
                        sf.Trimming = StringTrimming.Character;
                        sf.FormatFlags = StringFormatFlags.NoWrap | StringFormatFlags.MeasureTrailingSpaces;
                        szPostText = g.MeasureString((this._state == CellState.Flashed) ? this.fldFlashPostText : this.fldPostText, this.fldPostTextFont, (this.Bounds.Width - Convert.ToInt32(szPreText.Width)), sf);
                        g.DrawString((this._state == CellState.Flashed) ? this.fldFlashPostText : this.fldPostText, this.fldPostTextFont, fgPostTextBrush, this.Bounds, sf);
                    }

                    // Draw the main text (if there is any)
                    if (drawText)
                    {
                        sf.Alignment = this.HorizontalAlignment;
                        sf.Trimming = StringTrimming.EllipsisCharacter;
                        sf.FormatFlags = StringFormatFlags.NoWrap;

                        RectangleF rcMain = new RectangleF(this.Bounds.Left + (drawPreText ? szPreText.Width : 0),
                                                           this.Bounds.Top,
                                                           this.Bounds.Width - (drawPreText ? szPreText.Width : 0) - (drawPostText ? szPostText.Width : 0),
                                                           this.Bounds.Height);

                        g.DrawString(this.Text, ((this._state == CellState.Flashed) ? this.fldFlashFont : base.Font), fgTextBrush, rcMain, sf);
                    }
                }
            }


            /// <summary>
            /// Draw a solid background  
            /// </summary>
            /// <param name="g"></param>
            private void DrawPlain(Graphics g)
            {
                // Draw the backgroung based on the current state of the cell
                switch (this.CellState)
                {
                    case CellState.Flashed:
                        g.FillRectangle(ActiveGrid.Paintbox.Brush(this._row.Grid.UseFlashFadeOut ? this._fader.GetIterationColor(this._iterations) : this.fldFlashBackColor), CellBounds());
                        break;
                    case CellState.Highlighted:
                        DrawHighlighted(g);
                        break;
                    default:
                        g.FillRectangle(this._row.Grid.UseAlternateRowColors ? (this._row.AlternateRow ? ActiveGrid.Paintbox.AlternateBackgroundBrush : ActiveGrid.Paintbox.NormalBackgroundBrush) : ActiveGrid.Paintbox.NormalBackgroundBrush, CellBounds());
                        break;
                }
            }


            /// <summary>
            /// Draw the cell in the 'Highlighted' state.
            /// </summary>
            /// <param name="g"></param>
            private void DrawHighlighted(Graphics g)
            {
                g.FillRectangle(SystemBrushes.Highlight, CellBounds());
            }

            /// <summary>
            /// Draw the background using a gradient.
            /// </summary>
            /// <param name="g"></param>
            private void DrawGradient(Graphics g)
            {
                using (LinearGradientBrush bgBrush = new LinearGradientBrush(CellBounds(),
                            (this.CellState == CellState.Normal) ? ActiveGrid.Paintbox.GradientStartColor : this.fldFlashGradientStartColor,
                            (this.CellState == CellState.Normal) ? ActiveGrid.Paintbox.GradientEndColor : this.fldFlashGradientEndColor,
                            (this.CellState == CellState.Normal) ? ActiveGrid.Paintbox.RowLinearGradientMode : this.fldFlashLinearGradientMode))
                {
                    g.FillRectangle(bgBrush, bgBrush.Rectangle);
                }
            }

            #endregion

            #region --- Background Timer ------------------------------

            /// <summary>
            /// Background timer used to handle the duration of the cell flash.
            /// </summary>
            private System.Threading.Timer _flashTimer = null;

            /// <summary>
            /// Creates a new background timer that will callback when the flash duration has expired.
            /// </summary>
            /// <returns>true if the timer was initialized successfully; otherwise, false</returns>
            private void StartBackgroundTimer()
            {
                // Do we have a callback method 
                if (this.callback != null)
                {
                    FlashOn();

                    ActiveCellState state = new ActiveCellState(this._row.Grid.UseFlashFadeOut, ActiveCellFader.DEFAULT_TOTAL_ITERATIONS, this._row.Grid.UseFlashFadeOut ? (this._row.Grid.FlashDuration / ActiveCellFader.DEFAULT_TOTAL_ITERATIONS) : this._row.Grid.FlashDuration);

                    // Start the timer with the required configuration.
                    this._flashTimer = new System.Threading.Timer(callback, state, state.Interval, Timeout.Infinite);
                }
            }

            /// <summary>
            /// Callback method for the cell's background timer.
            /// N.B. This method will be called on a different thread to the one that
            /// initialized the timer.
            /// </summary>
            /// <param name="state"></param>
            private void flashTimerTimeout(object state)
            {
                ActiveCellState cellState = state as ActiveCellState;

                if (cellState == null)
                {
                    // The state object should always be non-null but just in
                    // case this ever happens simply dispose of the timer.
                    if (this._flashTimer != null)
                    {
                        this._flashTimer.Dispose();
                        this._flashTimer = null;
                    }
                }
                else
                {
                    // Is the 'Fade-Out' effect enabled?
                    if (cellState.UseFadeOut)
                    {
                        // This bit of strange logic is to handle the situation when the contents
                        // of a cell are changed part-way through the fade effect.
                        // When this happens the fade cycle must be reset to the start and timing
                        // begins again from scratch.
                        cellState.IterationsRemaining = this._iterations;
                        cellState.DecrementIterations();
                        this._iterations = cellState.IterationsRemaining;

                        // Have we finished fading-out so that we can dispose of the timer?
                        if (cellState.CanDispose)
                        {
                            FlashOff();

                            cellState.Disposed = true;

                            if (this._flashTimer != null)
                            {
                                this._flashTimer.Dispose();
                                this._flashTimer = null;
                            }
                        }
                        else if (!cellState.Disposed)
                        {
                            // Schedule the next callback event.
                            if (this._flashTimer != null)
                                this._flashTimer.Change(cellState.Interval, Timeout.Infinite);
                        }
                    }
                    else
                    {
                        FlashOff();

                        cellState.Disposed = true;

                        if (this._flashTimer != null)
                        {
                            this._flashTimer.Dispose();
                            this._flashTimer = null;
                        }
                    }
                }

                // Redraw the cell in a thread-safe manner.
                InvalidateCell();
            }

            #endregion

            #region --- Public Properties -----------------------------

            #region --- Colours ---------------------------------------

            /// <summary>
            /// Gets or sets the foreground color for the pre-text string when it is in a normal state.
            /// </summary>
            public Color PreTextForeColor
            {
                get { return this.fldPreTextForeColor;  }
                set { this.fldPreTextForeColor = value; }
            }

            /// <summary>
            /// Gets or sets the foreground color for the post-text string when it is in a normal state.
            /// </summary>
            public Color PostTextForeColor
            {
                get { return this.fldPostTextForeColor;  }
                set { this.fldPostTextForeColor = value; }
            }

            /// <summary>
            /// Gets or sets the foreground color for the pre-text string when it is in a 'flashed' state.
            /// </summary>
            public Color FlashPreTextForeColor
            {
                get { return this.fldFlashPreTextForeColor;  }
                set { this.fldFlashPreTextForeColor = value; }
            }

            /// <summary>
            /// Gets or sets the foreground color for the post-text string when it is in a 'flashed' state.
            /// </summary>
            public Color FlashPostTextForeColor
            {
                get { return this.fldFlashPostTextForeColor;  }
                set { this.fldFlashPostTextForeColor = value; }
            }

            /// <summary>
            /// Gets or sets the foreground color of the cell while it is in a 'flashed' state.
            /// </summary>
            public Color FlashForeColor
            {
                get { return this.fldFlashForeColor;  }
                set { this.fldFlashForeColor = value; }
            }

            /// <summary>
            /// Gets or sets the background color of the cell while it is in a 'flashed' state.
            /// </summary>
            public Color FlashBackColor
            {
                get { return this.fldFlashBackColor;  }
                set 
                { 
                    this.fldFlashBackColor = value; 
                    if(this._fader!= null)
                        this._fader.StartColor = value; 
                }
            }

            /// <summary>
            /// Gets or sets the start colour of the background gradient of the cell when
            /// it is in the normal state
            /// </summary>
            public Color GradientStartColor
            {
                get { return this.fldGradientStartColor;  }
                set { this.fldGradientStartColor = value; }
            }

            /// <summary>
            /// Gets or sets the end colour of the background gradient of the cell when
            /// it is in the normal state
            /// </summary>
            public Color GradientEndColor
            {
                get { return this.fldGradientEndColor;  }
                set { this.fldGradientEndColor = value; }
            }

            /// <summary>
            /// Gets or sets the start colour of the background gradient of the cell when
            /// it is in the 'flashed' state
            /// </summary>
            public Color FlashGradientStartColor
            {
                get { return this.fldFlashGradientStartColor;  }
                set { this.fldFlashGradientStartColor = value; }
            }

            /// <summary>
            /// Gets or sets the end colour of the background gradient of the cell when
            /// it is in the 'flashed' state
            /// </summary>
            public Color FlashGradientEndColor
            {
                get { return this.fldFlashGradientEndColor;  }
                set { this.fldFlashGradientEndColor = value; }
            }

            #endregion

            #region --- Fonts -----------------------------------------

            /// <summary>
            /// Gets or sets the font used in the text of the cell when it is being flashed.
            /// </summary>
            public Font FlashFont
            {
                get { return this.fldFlashFont; }
                set { this.fldFlashFont = value; }
            }

            /// <summary>
            /// Gets or sets the font used for the pre-text string of the cell when it is in a normal state.
            /// </summary>
            public Font PreTextFont
            {
                get { return this.fldPreTextFont; }
                set { this.fldPreTextFont = value; }
            }

            /// <summary>
            /// Gets or sets the font used for the post-text string of the cell when it is in a normal state.
            /// </summary>
            public Font PostTextFont
            {
                get { return this.fldPostTextFont; }
                set { this.fldPostTextFont = value; }
            }

            #endregion

            #region --- Strings ---------------------------------------

            /// <summary>
            /// Main text of the cell
            /// </summary>
            public new String Text
            {
                get
                {
                    string strVal = String.Empty;
                    if (this._useDecimal)
                    {
                        strVal = String.Format(this.fldFormat, this._decValue);

                        // Do we display zero values?
                        if (this._decValue == Decimal.Zero && !this.fldDisplayZeroValues)
                            strVal = String.Empty;
                    }
                    else
                    {
                        strVal = String.Format(this.fldFormat, base.Text);
                    }

                    return strVal;
                }
                set
                {
                    this._useDecimal = false;
                    base.Text = value;
                    // Has the value changed?
                    if (!base.Text.Equals(String.IsNullOrEmpty(value) ? String.Empty : value))
                    {
                        base.Text = String.IsNullOrEmpty(value) ? String.Empty : value;

                        Flash();
                    }
                }
            }

            /// <summary>
            /// Gets or sets the format specifier for the cell text.
            /// </summary>
            public String Format
            {
                get { return this.fldFormat; }
                set { this.fldFormat = String.IsNullOrEmpty(value) ? DEFAULT_FORMAT_SPECIFIER : "{0:" + value.Trim() + "}"; }
            }


            /// <summary>
            /// Gets or sets the text that appears at the far left of the cell when it is in a normal state.
            /// </summary>
            public String PreText
            {
                get { return this.fldPreText; }
                set { this.fldPreText = (value == null) ? String.Empty : value.TrimEnd(); }
            }

            /// <summary>
            /// Gets or sets the text that appears at the far left of the cell when it is being 'flashed'.
            /// </summary>
            public String FlashPreText
            {
                get { return this.fldFlashPreText; }
                set { this.fldFlashPreText = (value == null) ? String.Empty : value.TrimEnd(); }
            }

            /// <summary>
            /// Gets or sets the text that appears at the far right of the cell when it is in a normal state.
            /// </summary>
            public String PostText
            {
                get { return this.fldPostText; }
                set { this.fldPostText = (value == null) ? String.Empty : value.TrimStart(); }
            }

            /// <summary>
            /// Gets or sets the text that appears at the far right of the cell when it is being 'flashed'.
            /// </summary>
            public String FlashPostText
            {
                get { return this.fldFlashPostText; }
                set { this.fldFlashPostText = (value == null) ? String.Empty : value.TrimStart(); }
            }

            #endregion

            #region --- Miscellaneous ---------------------------------

            /// <summary>
            /// Gets the row to which this cell belongs
            /// </summary>
            public ActiveRow Row
            {
                get { return this._row; }
            }

            /// <summary>
            /// Gets the column to which this cell belongs
            /// </summary>
            public ActiveColumnHeader Column
            {
                get { return this._column; }
            }

            /// <summary>
            /// Gets or sets the vertical alignment of all text within the cell.
            /// </summary>
            public StringAlignment VerticalAlignment
            {
                get { return this.fldVerticalAlignment; }
                set { this.fldVerticalAlignment = value; }
            }

            /// <summary>
            /// Gets or sets the horizontal alignment of all text within the cell.
            /// </summary>
            public StringAlignment HorizontalAlignment
            {
                get { return this.fldHorizontalAlignment; }
                set { this.fldHorizontalAlignment = value; }
            }

            /// <summary>
            /// Gets or sets the Decimal value to display within the cell.
            /// </summary>
            public Decimal DecimalValue
            {
                get { return this._decValue; }
                set
                {
                    this._useDecimal = true;

                    // Has the value changed?
                    if (this._decValue != value)
                    {
                        this._decValue = value;

                        this.fldUseNegativeForeColor = (this._decValue < Decimal.Zero);

                        Flash();
                    }
                }
            }

            /// <summary>
            /// Gets a flag indicating whether the cell contains a decimal value or not
            /// </summary>
            public Boolean ValueIsDecimal
            {
                get { return this._useDecimal; }
            }

            /// <summary>
            /// Gets or sets the linear gradient mode for the background of the cell when it
            /// is in a flashed state.
            /// </summary>
            public LinearGradientMode FlashLinearGradientMode
            {
                get { return this.fldFlashLinearGradientMode; }
                set { this.fldFlashLinearGradientMode = value; }
            }

            /// <summary>
            /// Gets or sets the current state of the cell
            /// </summary>
            public CellState CellState
            {
                get { lock (this.synchRoot) { return this._state;  } }
                set { lock (this.synchRoot) { this._state = value; } }
            }

            /// <summary>
            /// Gets or sets the current style of the cell
            /// </summary>
            public CellStyle CellStyle
            {
                get { return this.CellStyle; }
                set { this.CellStyle = value; }
            }

            #endregion

            #endregion

            #region --- Nested Class ActiveCellFader ------------------

            /// <summary>
            /// Class that handles the Fade-effect logic for the cell.
            /// </summary>
            private class ActiveCellFader
            {
                #region --- Class Data -----------------------------------

                /// <summary>
                /// The number of iterations to use for the fade effect
                /// </summary>
                public static int DEFAULT_TOTAL_ITERATIONS = 10;
                /// <summary>
                /// The colour at the start of the fade.
                /// </summary>
                private Color _startColor;
                /// <summary>
                /// The colour at the end of the fade.
                /// </summary>
                private Color _endColor;
                /// <summary>
                /// The total number of iterations in the fade effect
                /// </summary>
                private int _iterations;
                /// <summary>
                /// The difference to be added to the Red component during each iteration
                /// </summary>
                private int _deltaR;
                /// <summary>
                /// The difference to be added to the Green component during each iteration
                /// </summary>
                private int _deltaG;
                /// <summary>
                /// The difference to be added to the Blue component during each iteration
                /// </summary>
                private int _deltaB;

                #endregion

                #region --- Constructor ----------------------------------

                /// <summary>
                /// Default constructor (White background, no fade)
                /// </summary>
                public ActiveCellFader()
                    : this(Color.White, Color.White, 0)
                {
                }

                /// <summary>
                /// Construcor fading to a white background from a given starting colour.
                /// </summary>
                /// <param name="startColor">The starting colour of the fade</param>
                public ActiveCellFader(Color startColor)
                    : this(startColor, Color.White, DEFAULT_TOTAL_ITERATIONS)
                {
                }

                /// <summary>
                /// Constructor fading from the start and end colours provided
                /// </summary>
                /// <param name="startColor">The starting colour of the fade</param>
                /// <param name="endColor">The finishing colour of the fade</param>
                public ActiveCellFader(Color startColor, Color endColor)
                    : this(startColor, endColor, DEFAULT_TOTAL_ITERATIONS)
                {
                }

                /// <summary>
                /// Constructor fading from the start and end colours provided using the 
                /// given number of iterations
                /// </summary>
                /// <param name="startColor">The starting colour of the fade</param>
                /// <param name="endColor">The finishing colour of the fade</param>
                /// <param name="iterations">The number of iterations in the fade</param>
                public ActiveCellFader(Color startColor, Color endColor, int iterations)
                {
                    this._startColor = startColor;
                    this._endColor = endColor;
                    this._iterations = (iterations < 0) ? 0 : iterations;

                    CalculateDeltas();
                }

                #endregion

                #region --- Public Methods -------------------------------

                /// <summary>
                /// Retrieves the colour associated with the given iteration of the fade.
                /// </summary>
                /// <param name="iteration">The fade iteration</param>
                /// <returns></returns>
                public Color GetIterationColor(int iteration)
                {
                    if (iteration <= 0)
                        return this._endColor;

                    if(iteration >= this._iterations)
                        return this._startColor;

                    int R = this._startColor.R - ((this._iterations - iteration) * this._deltaR);
                    int G = this._startColor.G - ((this._iterations - iteration) * this._deltaG);
                    int B = this._startColor.B - ((this._iterations - iteration) * this._deltaB);

                    return Color.FromArgb(R, G, B);
                }


                #endregion

                #region --- Private Methods ------------------------------

                /// <summary>
                /// Calculate the difference to be added to each of the colour components
                /// during a single iteration.
                /// </summary>
                private void CalculateDeltas()
                {
                    this._deltaR = 0;
                    this._deltaG = 0;
                    this._deltaB = 0;

                    if (this._startColor == this._endColor)
                        this._iterations = 0;

                    if (this._iterations > 0)
                    {
                        this._deltaR = (this._startColor.R - this._endColor.R) / this._iterations;
                        this._deltaG = (this._startColor.G - this._endColor.G) / this._iterations;
                        this._deltaB = (this._startColor.B - this._endColor.B) / this._iterations;
                    }
                }

                #endregion

                #region --- Public Properties ----------------------------

                /// <summary>
                /// Gets or sets the starting colour of the fade effect.
                /// </summary>
                public Color StartColor
                {
                    get { return this._startColor; }
                    set
                    {
                        if (this._startColor != value)
                        {
                            this._startColor = value;
                            CalculateDeltas();
                        }
                    }
                }

                /// <summary>
                /// Gets or sets the finishing colour of the fade effect.
                /// </summary>
                public Color EndColor
                {
                    get { return this._endColor; }
                    set
                    {
                        if (this._endColor != value)
                        {
                            this._endColor = value;
                            CalculateDeltas();
                        }
                    }
                }

                /// <summary>
                /// Gets or sets the total number of iterations in the fade effect.
                /// </summary>
                public Int32 TotalIterations
                {
                    get { return this._iterations; }
                    set
                    {
                        if (this._iterations != value)
                        {
                            this._iterations = value;
                            CalculateDeltas();
                        }
                    }

                }

                #endregion
            }

            #endregion

            #region --- Nested Class ActiveCellState ------------------

            /// <summary>
            /// Class to store the Fade-state of an ActiveCell instance for use in timer callbacks.
            /// </summary>
            private class ActiveCellState
            {
                #region --- Class Data --------------------------------

                /// <summary>
                /// Flag to indicate if the fade effect should be used.
                /// </summary>
                private bool _useFadeOut;
                /// <summary>
                /// The number of iterations remaining
                /// </summary>
                private int _iterations;
                /// <summary>
                /// The interval to wait between iterations
                /// </summary>
                private int _interval;
                /// <summary>
                /// Flag to indicate that the fader has been disposed of.
                /// </summary>
                private bool _isDisposed;

                #endregion

                #region --- Constructor -------------------------------

                /// <summary>
                /// Default constructor
                /// </summary>
                /// <param name="useFadeOut">Indicates whether a fade-effect is required</param>
                /// <param name="iterations">The total number of iterations to use in the fade-effect</param>
                /// <param name="interval">The interval to wait between callbacks</param>
                public ActiveCellState(bool useFadeOut, int iterations, int interval)
                {
                    this._useFadeOut = useFadeOut;
                    this._iterations = iterations;
                    this._interval = interval;
                    this._isDisposed = false;
                }

                #endregion

                #region --- Public Methods ----------------------------

                /// <summary>
                /// Increment the number of iterations remaining
                /// </summary>
                /// <returns>The number of iterations remaining</returns>
                public int IncrementIterations()
                {
                    return Interlocked.Increment(ref this._iterations);
                }

                /// <summary>
                /// Decrements the number of iterations remaining
                /// </summary>
                /// <returns>The number of iterations remaining</returns>
                public int DecrementIterations()
                {
                    return (this._iterations > 0 ? Interlocked.Decrement(ref this._iterations) : this._iterations);
                }

                #endregion

                #region --- Properties --------------------------------

                /// <summary>
                /// Gets a flag to indicate if the fade-effect is being used.
                /// </summary>
                public Boolean UseFadeOut
                {
                    get { return this._useFadeOut; }
                }

                /// <summary>
                /// Gets or sets the number of iterations remaining.
                /// </summary>
                public Int32 IterationsRemaining
                {
                    get { return this._iterations;  }
                    set { Interlocked.Exchange( ref this._iterations, value); }
                }

                /// <summary>
                /// Gets the time interval to wait between callbacks.
                /// </summary>
                public Int32 Interval
                {
                    get { return this._interval;  }
                }

                /// <summary>
                /// Gets a flag to indicate if the current timer can be disposed of.
                /// </summary>
                public Boolean CanDispose
                {
                    get { return (this._useFadeOut ? (this._iterations <= 0) : true);  }
                }

                /// <summary>
                /// Gets or sets a flag to indicate if the current timer has been disposed of.
                /// </summary>
                public Boolean Disposed
                {
                    get { return this._isDisposed;  }
                    set { this._isDisposed = value; }
                }

                #endregion
            }

            #endregion
        }

        #endregion

        #region --- Nested Class LinkLabelCell --------------------

        /// <summary>
        /// Class to provide LinkLabel functionality to the row header.
        /// </summary>
        private class LinkLabelCell
        {
            #region --- Class Data ------------------------------------

            /// <summary>
            /// The bounding rectangle of the text
            /// </summary>
            private RectangleF _rcText;
            /// <summary>
            /// The bounding rectangle of the cell
            /// </summary>
            private Rectangle _parentRect;
            /// <summary>
            /// Flag to indicate if the cursor is currently over the text
            /// </summary>
            private bool _mouseOver = false;
            /// <summary>
            /// Flag to indicate whether the cursor status has changed
            /// i.e. whether it is over or not-over the text
            /// </summary>
            private bool _changed = false;
            /// <summary>
            /// The brush to use for drawing the text.
            /// </summary>
            private Brush _linkBrush = Brushes.Blue;

            #endregion

            #region --- Delegates -------------------------------------

            public event OnLeftMouseClickHandler OnLeftMouseClick;
            public delegate void OnLeftMouseClickHandler(object sender, EventArgs e);

            public event OnRightMouseClickHandler OnRightMouseClick;
            public delegate void OnRightMouseClickHandler(object sender, EventArgs e);

            #endregion

            #region --- Public Constructors ---------------------------

            /// <summary>
            /// Default constructor.
            /// </summary>
            /// <param name="rc">The bounding rectangle of the parent cell</param>
            public LinkLabelCell(Rectangle rc)
            {
                this._parentRect = rc;
            }

            #endregion

            #region --- Public Methods --------------------------------

            public bool OnMouseClick(System.Windows.Forms.MouseEventArgs e)
            {
                bool handled = false;

                if (e!= null && Contains(e.Location))
                {
                    switch (e.Button)
                    {
                        case System.Windows.Forms.MouseButtons.Left:
                            OnLeftMouseClickHandler onLeftMouseClick = OnLeftMouseClick;
                            if (onLeftMouseClick != null)
                                onLeftMouseClick(this, EventArgs.Empty);
                            handled = true;
                            break;
                        case System.Windows.Forms.MouseButtons.Middle:
                            // System.Windows.Forms.MessageBox.Show("Middle Mouse Click");
                            break;
                        case System.Windows.Forms.MouseButtons.Right:
                            OnRightMouseClickHandler onRightMouseClick = OnRightMouseClick;
                            if (onRightMouseClick != null)
                                onRightMouseClick(this, EventArgs.Empty);
                            handled = true;
                            break;
                        case System.Windows.Forms.MouseButtons.XButton1:
                            // System.Windows.Forms.MessageBox.Show("XButton1 Mouse Click");
                            break;
                        case System.Windows.Forms.MouseButtons.XButton2:
                            // System.Windows.Forms.MessageBox.Show("XButton2 Mouse Click");
                            break;
                        default:
                            break;
                    }
                }

                return handled;
            }

            public bool MouseOver(PointF pt)
            {
                if (this._mouseOver != Contains(pt))
                {
                    this._mouseOver = Contains(pt);
                    this._changed = true;
                    this._linkBrush = this._mouseOver ? Brushes.Purple : Brushes.Blue;
                }

                return this._mouseOver;
            }


            public void Draw(Graphics g, string text, Font font, Rectangle bounds, StringFormat sf, bool selected)
            {
                this._parentRect = bounds;

                if (selected)
                {
                    g.DrawString(text, font, SystemBrushes.HighlightText, this._parentRect, sf);
                }
                else
                {
                    g.DrawString(text, font, this._linkBrush, this._parentRect, sf);
                }

                PointF pt = this._parentRect.Location;
                SizeF size = g.MeasureString(text, font, this._parentRect.Location, sf);
                switch(sf.LineAlignment)
                {
                    case StringAlignment.Near:
                        pt = this._parentRect.Location;
                        break;
                    case StringAlignment.Far:
                        pt = new PointF( (this._parentRect.X + this._parentRect.Width - size.Width), this._parentRect.Y );
                        break;
                    case StringAlignment.Center:
                        pt = new PointF( (this._parentRect.X + (this._parentRect.Width - size.Width)/2), this._parentRect.Y );
                        break;
                }

                // Set the bounding rectangle of the text
                this._rcText = new RectangleF(pt, size);
            }

            #endregion

            #region --- Private Methods -------------------------------

            /// <summary>
            /// Determines whether the given point lies within the bounding 
            /// rectangle of the text
            /// </summary>
            /// <param name="pt">The location point to test</param>
            /// <returns>true if the point lies over the text; otherwise, false</returns>
            private bool Contains(PointF pt)
            {
                return this._rcText.Contains(pt);
            }

            #endregion

            #region --- Public Properties -----------------------------

            /// <summary>
            /// Gets a flag to indicate if the status of the link has changed.
            /// </summary>
            public Boolean Changed
            {
                get { return this._changed; }
            }

            #endregion
        }

        #endregion
    }

    #endregion

    #region --- Class RowHeaderEventArgs -----------------------------

    public class RowHeaderEventArgs : EventArgs
    {
        #region --- Class Data ---------------------------

        private string _rowName;
        private int _rowIndex;
        private object _rowTag;

        #endregion

        #region --- Constructor --------------------------

        public RowHeaderEventArgs(int index, string name, object tag)
        {
            this._rowIndex = index;
            this._rowName = name;
            this._rowTag = tag;
        }

        #endregion

        #region --- Properties ---------------------------

        public String RowName
        {
            get { return this._rowName; }
        }

        public Int32 RowIndex
        {
            get { return this._rowIndex; }
        }

        public Object RowTag
        {
            get { return this._rowTag;  }
        }

        #endregion
    }

    #endregion

    #region --- Custom Exception Classes -----------------------------

    class DuplicateRowNameException : ApplicationException
    {
        public DuplicateRowNameException(string message)
            : base(message)
        {
        }

        public DuplicateRowNameException(string message, Exception innerException)
            : base(message, innerException)
        {
        }
    }

    class DuplicateColumnNameException : ApplicationException
    {
        public DuplicateColumnNameException(string message)
            : base(message)
        {
        }

        public DuplicateColumnNameException(string message, Exception innerException)
            : base(message, innerException)
        {
        }
    }

    class DuplicateCellNameException : ApplicationException
    {
        public DuplicateCellNameException(string message)
            : base(message)
        {
        }

        public DuplicateCellNameException(string message, Exception innerException)
            : base(message, innerException)
        {
        }
    }

    #endregion

    #region --- ActiveGridItemComparer -------------------------------

    // Implements the manual sorting of items by columns.
    class ActiveGridItemComparer : System.Collections.IComparer
    {
        #region --- Class Data -----------------------------

        private int _col;
        private ActiveColumnHeader _columnHeader;
        private SortOrderEnum _sortOrder;

        #endregion

        #region --- Constructors ---------------------------

        public ActiveGridItemComparer()
        {
            this._col = 0;
            this._sortOrder = SortOrderEnum.Ascending;
        }

        public ActiveGridItemComparer(ActiveColumnHeader columnHeader)
        {
            this._columnHeader = columnHeader;
            this._sortOrder = columnHeader.SortOrder;
            this._col = columnHeader.Index;
        }

        #endregion

        #region --- IComparer ------------------------------

        public int Compare(object x, object y)
        {
            int compare = 0;

            ActiveRow lvi1 = x as ActiveRow;
            ActiveRow lvi2 = y as ActiveRow;

            if (lvi1 != null && lvi2 != null)
            {
                if (this._col == 0)
                {
                    if (this._sortOrder == SortOrderEnum.Ascending)
                        compare = String.Compare(lvi1.Text, lvi2.Text);
                    else
                        compare = String.Compare(lvi2.Text, lvi1.Text);
                }
                else if (lvi1.SubItems.Count > this._col && lvi2.SubItems.Count > this._col)
                {
                    // Are we comparing devima or string values?
                    if (lvi1.SubItems[this._col].ValueIsDecimal && lvi2.SubItems[this._col].ValueIsDecimal)
                    {
                        if (this._sortOrder == SortOrderEnum.Ascending)
                            compare = Decimal.Compare(lvi1.SubItems[this._col].DecimalValue, lvi2.SubItems[this._col].DecimalValue);
                        else
                            compare = Decimal.Compare(lvi2.SubItems[this._col].DecimalValue, lvi1.SubItems[this._col].DecimalValue);
                    }
                    else
                    {
                        if (this._sortOrder == SortOrderEnum.Ascending)
                            compare = String.Compare(lvi1.SubItems[this._col].Text, lvi2.SubItems[this._col].Text);
                        else
                            compare = String.Compare(lvi2.SubItems[this._col].Text, lvi1.SubItems[this._col].Text);
                    }
                }
            }

            return compare;
        }

        #endregion
    }

    #endregion

}

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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Unknown
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions