13:05 ET Dow -154.48 at 10309.92, Nasdaq -37.61 at 2138.44, S&P -19.130 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 0 1 100001 0 1 0 1 1 0 1 0 00 0 1 1 1 0 1 100001 0 1 1 100001 13:05 ET Dow -154.48 at 10309.92, Nasdaq -37.61 at 2138.44, S&P -19.1313:05 ET Dow -154.48 at 10309.92, Nasdaq -37.61 at 2138.44, S&P -19.13

.

.

Tuesday, September 27, 2011

Real-Time Data Grid in C# - From The Code Project by Jason Mason - Awesome Tutorial - Google It for Pics, Etc.

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

}