#region COPYRIGHT
//
//     THIS IS GENERATED BY TEMPLATE
//     
//     AUTHOR  :     ROYE
//     DATE       :     2010
//
//     COPYRIGHT (C) 2010, TIANXIAHOTEL TECHNOLOGIES CO., LTD. ALL RIGHTS RESERVED.
//
#endregion

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.APIs;
using System.Diagnostics;
using System.Threading;
using System.Win32;

namespace TX.Framework.WindowUI.Controls
{
    [ToolboxBitmap(typeof(ListView))]
    public class TreeListView : TXListView
    {
        private delegate TreeListViewItem[] ItemArrayHandler();

        private IContainer components;
        private CheckBoxesTypes _CheckBoxes = CheckBoxesTypes.None;
        private ImageList _SmallImagList = null;
        private SortOrder _Sorting = SortOrder.Ascending;
        private TreeListViewExpandMethod _ExpandMethod = TreeListViewExpandMethod.EntireItemDbleClick;
        private DateTime _LastDoubleClick;
        private DateTime _DblClickTime = DateTime.Now;
        private CustomEdit _CustomEdit;
        private TreeListViewItemCollection _Items;
        private Point _MouseScrollPosition = new Point(0, 0);
        private Color _PlusMinusLineColor = Color.DarkGray;
        private int _PlusMinusLinePattern = 0;
        private bool _HasMarquee = false;
        private bool _InEdit;
        private bool _ShowPlusMinus = true;
        private bool _UseXPHighLightStyle = true;
        private string _PathSeparator = "\\";
        private bool _Scrollable = true;
        internal TreeListViewItem _SelectionMark = null;
        internal CheckDirection CheckDirection = CheckDirection.None;
        internal EditItemInformations _EditedItem = new EditItemInformations();
        internal EditItemInformations _LastItemClicked;
        internal bool _Updating = false;
        internal bool _SkipMouseDownEvent = false;
        internal bool FreezeCheckBoxes = false;
        private ImageList imageList1;
        internal ImageList plusMinusImageList;
        internal int _Comctl32Version;

        #region Events

        /// <summary>
        /// Occurs when the label for an item is edited by the user.
        /// </summary>
        [Description("Occurs when the label for an item is edited by the user.")]
        public new event TreeListViewLabelEditEventHandler AfterLabelEdit;

        /// <summary>
        /// Occurs when the user starts editing the label of an item.
        /// </summary>
        [Description("Occurs when the user starts editing the label of an item."), Browsable(true)]
        public new event TreeListViewBeforeLabelEditEventHandler BeforeLabelEdit;

        /// <summary>
        /// Occurs before the tree node is collapsed.
        /// </summary>
        [Description("Occurs before the tree node is collapsed")]
        public event TreeListViewCancelEventHandler BeforeExpand;

        /// <summary>
        /// Occurs before the tree node is collapsed.
        /// </summary>
        [Description("Occurs before the tree node is collapsed")]
        public event TreeListViewCancelEventHandler BeforeCollapse;

        /// <summary>
        /// Occurs after the tree node is expanded
        /// </summary>
        [Description("Occurs after the tree node is expanded")]
        public event TreeListViewEventHandler AfterExpand;

        /// <summary>
        /// Occurs after the tree node is collapsed
        /// </summary>
        [Description("Occurs after the tree node is collapsed")]
        public event TreeListViewEventHandler AfterCollapse;

        #endregion

        public TreeListView()
            : base()
        {
            InitializeComponent();
            if (!IsHandleCreated)
            {
                CreateHandle();
            }
            _Items = new TreeListViewItemCollection(this);
            _Items.SortOrder = _Sorting;
            _Comctl32Version = NativeMethods.GetMajorVersion();

            int style = NativeMethods.SendMessage(Handle, (int)ListViewMessages.GETEXTENDEDLISTVIEWSTYLE, 0, 0);
            style |= (int)(ListViewExtendedStyles.INFOTIP | ListViewExtendedStyles.LABELTIP);
            NativeMethods.SendMessage(Handle, (int)ListViewMessages.SETEXTENDEDLISTVIEWSTYLE, 0, style);
        }

        #region OnEvents

        protected virtual void OnAfterLabelEdit(TreeListViewLabelEditEventArgs e)
        {
            if (AfterLabelEdit != null)
            {
                AfterLabelEdit(this, e);
            }
        }

        protected override void OnAfterLabelEdit(LabelEditEventArgs e)
        {
            throw new Exception("Please use OnAfterLabelEdit(TreeListViewLabelEditEventArgs e)");
        }

        protected virtual void OnBeforeLabelEdit(TreeListViewBeforeLabelEditEventArgs e)
        {
            if (BeforeLabelEdit != null)
            {
                BeforeLabelEdit(this, e);
            }
        }

        protected override void OnBeforeLabelEdit(LabelEditEventArgs e)
        {
            throw new Exception("Please use OnBeforeLabelEdit(TreeListViewLabelEditEventArgs e)");
        }

        protected virtual void OnBeforeExpand(TreeListViewCancelEventArgs e)
        {
            if (BeforeExpand != null)
            {
                BeforeExpand(this, e);
            }
        }

        protected virtual void OnAfterExpand(TreeListViewEventArgs e)
        {
            if (AfterExpand != null)
            {
                AfterExpand(this, e);
            }
        }

        protected virtual void OnBeforeCollapse(TreeListViewCancelEventArgs e)
        {
            if (BeforeCollapse != null)
            {
                BeforeCollapse(this, e);
            }
        }

        protected virtual void OnAfterCollapse(TreeListViewEventArgs e)
        {
            if (AfterCollapse != null)
            {
                AfterCollapse(this, e);
            }
        }

        #endregion

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (!_SkipMouseDownEvent)
            {
                base.OnMouseDown(e);
            }
        }

        internal void RaiseBeforeExpand(TreeListViewCancelEventArgs e)
        {
            OnBeforeExpand(e);
        }

        internal void RaiseBeforeCollapse(TreeListViewCancelEventArgs e)
        {
            OnBeforeCollapse(e);
        }

        internal void RaiseAfterExpand(TreeListViewEventArgs e)
        {
            OnAfterExpand(e);
        }

        internal void RaiseAfterCollapse(TreeListViewEventArgs e)
        {
            OnAfterCollapse(e);
        }

        protected override void OnSelectedIndexChanged(EventArgs e)
        {
            base.OnSelectedIndexChanged(e);
            this.Invalidate(true);
        }

        #region WndProc

        protected override void WndProc(ref Message m)
        {
            TreeListViewItem item = null;
            Rectangle rec;
            switch ((WindowMessages)m.Msg)
            {
                #region Notify

                case WindowMessages.NOTIFY:
                case (WindowMessages)ReflectedMessages.NOTIFY:
                    NMHDR nmhdr = (NMHDR)m.GetLParam(typeof(NMHDR));
                    NMHEADER nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
                    switch ((ListViewNotifications)nmhdr.code)
                    {
                        #region ListViewNotifications.MarqueeBegin

                        case ListViewNotifications.MARQUEEBEGIN:
                            if ((MouseButtons & MouseButtons.Left) != MouseButtons.Left)
                                m.Result = (IntPtr)1;
                            else
                                _HasMarquee = true;
                            break;

                        #endregion

                        #region ListViewNotifications.ItemChanging

                        case ListViewNotifications.ITEMCHANGING:
                            NMLISTVIEW nmlistview = (NMLISTVIEW)m.GetLParam(typeof(NMLISTVIEW));
                            if (nmlistview.iItem < 0) break;
                            if ((item = GetTreeListViewItemFromIndex(nmlistview.iItem)) == null) break;
                            bool cancel = false;
                            if (nmlistview.Select)
                            {
                                if (_SelectionMark == null)
                                {
                                    _SelectionMark = item;
                                }
                                else if (!_SelectionMark.Visible)
                                {
                                    _SelectionMark = item;
                                }
                                if (HasMarquee)
                                {
                                    item.Focused = true;
                                }
                            }
                            else if (nmlistview.UnSelect && HasMarquee)
                            {
                                if (item.NextVisibleItem != null)
                                {
                                    if (item.NextVisibleItem.Selected)
                                    {
                                        item.NextVisibleItem.Focused = true;
                                    }
                                }
                                if (item.PrevVisibleItem != null)
                                {
                                    if (item.PrevVisibleItem.Selected)
                                    {
                                        item.PrevVisibleItem.Focused = true;
                                    }
                                }
                            }

                            #region Select after dbl click
                            // Disable the selection after a double click (normaly, if the control scrolls after
                            // a collapse, the new item under the cursor is automatically selected...)
                            if (_DblClickTime.AddMilliseconds(500).CompareTo(DateTime.Now) > 0 &&
                                (nmlistview.Select || nmlistview.Focus) &&
                                FocusedItem != item)
                                cancel = true;
                            #endregion

                            #region Wrong Level Select
                            if (((System.Win32.ListViewItemStates)nmlistview.uNewState & System.Win32.ListViewItemStates.SELECTED) == System.Win32.ListViewItemStates.SELECTED && MultiSelect)
                                if (SelectedIndices.Count > 0)
                                    if (GetTreeListViewItemFromIndex(nmlistview.iItem).Parent != SelectedItems[0].Parent)
                                        cancel = true;
                            #endregion

                            #region Check during selection

                            // Disable check boxes check when :
                            // - the Marquee selection tool is being used
                            // - the Ctrl or Shift keys are down
                            bool state = (nmlistview.uChanged & (uint)ListViewItemFlags.STATE) == (uint)ListViewItemFlags.STATE;
                            bool ctrlKeyDown = (ModifierKeys & Keys.Control) == Keys.Control;
                            bool shiftKeyDown = (ModifierKeys & Keys.Shift) == Keys.Shift;
                            if ((nmlistview.Check || nmlistview.UnCheck) &&
                                (HasMarquee || ctrlKeyDown || shiftKeyDown))
                            {
                                //									MessageBox.Show(this,
                                //										"uChanged = " + nmlistview->uChanged.ToString() + "\n\n" + 
                                //										"uOld = " + nmlistview->uOldState.ToString() + "\n" + 
                                //										"uNew = " + nmlistview->uChanged.ToString() + "\n\n" +
                                //										"OldCheck : " + (oldCheck ? "true" : "false") + "\n" + 
                                //										"NewCheck : " + (newCheck ? "true" : "false"));
                                cancel = true;
                            }
                            #endregion

                            if (cancel)
                            {
                                m.Result = (IntPtr)1;
                                return;
                            }
                            break;

                        #endregion

                        #region ListViewNotifications.BeginLabelEdit

                        case ListViewNotifications.BEGINLABELEDIT:
                            // Cancel label edit if the message is sent just after a double click
                            if (_LastDoubleClick.AddMilliseconds(450) > DateTime.Now)
                            {
                                Message canceledit = Message.Create(Handle, (int)ListViewMessages.CANCELEDITLABEL, IntPtr.Zero, IntPtr.Zero);
                                WndProc(ref canceledit);
                                m.Result = (IntPtr)1;
                                return;
                            }
                            item = _LastItemClicked.Item;
                            item.EnsureVisible();
                            // Add subitems if needed
                            while (item.SubItems.Count - 1 < _LastItemClicked.ColumnIndex) item.SubItems.Add("");
                            TreeListViewBeforeLabelEditEventArgs beforeed = new TreeListViewBeforeLabelEditEventArgs(
                                FocusedItem, _LastItemClicked.ColumnIndex, item.SubItems[_LastItemClicked.ColumnIndex].Text);
                            OnBeforeLabelEdit(beforeed);
                            if (beforeed.Cancel)
                            {
                                Message canceledit = Message.Create(Handle, (int)ListViewMessages.CANCELEDITLABEL, IntPtr.Zero, IntPtr.Zero);
                                WndProc(ref canceledit);
                                m.Result = (IntPtr)1;
                                return;
                            }
                            _InEdit = true;
                            // Get edit handle
                            Message mess = Message.Create(Handle, (int)ListViewMessages.GETEDITCONTROL, IntPtr.Zero, IntPtr.Zero);
                            WndProc(ref mess);
                            IntPtr edithandle = mess.Result;
                            _CustomEdit = new CustomEdit(edithandle, this, beforeed.Editor);
                            _EditedItem = new EditItemInformations(FocusedItem, beforeed.ColumnIndex, FocusedItem.SubItems[beforeed.ColumnIndex].Text);
                            m.Result = IntPtr.Zero;
                            return;

                        #endregion

                        #region ListViewNotifications.EndLabelEdit

                        case ListViewNotifications.ENDLABELEDIT:
                            if (_CustomEdit != null)
                                _CustomEdit.HideEditControl();
                            _CustomEdit = null;
                            _InEdit = false;
                            _EditedItem = new EditItemInformations();
                            m.Result = IntPtr.Zero;
                            return;

                        #endregion

                        #region CustomDraw

                        case (ListViewNotifications)NotificationMessages.CUSTOMDRAW:
                            base.WndProc(ref m);
                            //CustomDraw(ref m);
                            return;

                        #endregion

                        #region BeginScroll

                        case ListViewNotifications.BEGINSCROLL:
                            _Updating = true;
                            break;

                        #endregion

                        #region EndScroll

                        case ListViewNotifications.ENDSCROLL:
                            _Updating = false;
                            // Disable display bug with vertical lines (slow...)
                            //							if(ShowPlusMinus)
                            //							{
                            //								DrawPlusMinusItemsLines();
                            //								DrawPlusMinusItems();
                            //							}
                            break;

                        #endregion

                        #region HeaderControlNotifications.BeginDrag

                        case (ListViewNotifications)HeaderControlNotifications.BEGINDRAG:
                            nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
                            if (nmheader.iItem == 0)
                            {
                                m.Result = (IntPtr)1;
                                return;
                            }
                            break;

                        #endregion

                        #region HeaderControlNotifications.EndDrag

                        case (ListViewNotifications)HeaderControlNotifications.ENDDRAG:
                            nmheader = (NMHEADER)m.GetLParam(typeof(NMHEADER));
                            // Get mouse position in header coordinates
                            IntPtr headerHandle = (IntPtr)NativeMethods.SendMessage(Handle, (int)ListViewMessages.GETHEADER, IntPtr.Zero, IntPtr.Zero);
                            System.Win32.POINTAPI pointapi = new System.Win32.POINTAPI(MousePosition);
                            NativeMethods.ScreenToClient(headerHandle, ref pointapi);
                            // HeaderItem Rect
                            RECT headerItemRect = new RECT();
                            SendMessage(headerHandle, (int)HeaderControlMessages.GETITEMRECT, 0, ref headerItemRect);
                            int headerItemWidth = headerItemRect.right - headerItemRect.left;
                            // Cancel the drag operation if the first column is moved
                            // or destination is the first column
                            if (pointapi.X <= headerItemRect.left + headerItemWidth / 2 || nmheader.iItem == 0)
                            {
                                m.Result = (IntPtr)1;
                                return;
                            }
                            break;

                        #endregion

                        #region HeaderControlNotifications.Track / EndTrack

                        //						case (ListViewNotifications)HeaderControlNotifications.TRACK:
                        case (ListViewNotifications)HeaderControlNotifications.ENDTRACK:
                            Invalidate();
                            break;

                        #endregion
                    }

                    break;
                #endregion

                #region LButtonDown

                // Cancel the click on checkboxes if the item is not "checkable"
                case WindowMessages.LBUTTONDOWN:
                    if (Columns.Count == 0) break;
                    // Set the clickeditem and column
                    int colclicked = GetColumnAt(MousePosition);
                    if (colclicked == -1) colclicked = 0;
                    item = GetItemAtFullRow(PointToClient(MousePosition));
                    _LastItemClicked = new EditItemInformations(item, colclicked, "");
                    if (_SelectionMark == null || !_SelectionMark.Visible) _SelectionMark = item;
                    if (((KeyStatesMasks)(int)m.WParam & KeyStatesMasks.SHIFT) != KeyStatesMasks.SHIFT &&
                        !(((KeyStatesMasks)(int)m.WParam & KeyStatesMasks.CONTROL) == KeyStatesMasks.CONTROL &&
                        item.Parent != _SelectionMark.Parent))
                        _SelectionMark = item;
                    // Get where the mouse has clicked
                    LVHITTESTINFO lvhittest = new LVHITTESTINFO();
                    lvhittest.pt = new POINTAPI(PointToClient(MousePosition));
                    SendMessage(Handle, (Int32)ListViewMessages.HITTEST, 0, ref lvhittest);
                    if (item == null) break;
                    // Plus / Minus click
                    if (item.GetBounds(TreeListViewItemBoundsPortion.PlusMinus).Contains(PointToClient(MousePosition)) &&
                        ShowPlusMinus && item.Items.Count > 0 &&
                        Columns[0].Width > (item.Level + 1) * SystemInformation.SmallIconSize.Width)
                    {
                        Focus();
                        if (item.IsExpanded) item.Collapse();
                        else item.Expand();
                        OnMouseDown(new MouseEventArgs(MouseButtons.Left, 1, PointToClient(MousePosition).X, PointToClient(MousePosition).Y, 0));
                        return;
                    }
                    // Cancel mouse click if multiselection on a wrong item
                    if (SelectedIndices.Count > 0 &&
                        (((KeyStatesMasks)(int)m.WParam & KeyStatesMasks.SHIFT) == KeyStatesMasks.SHIFT ||
                        ((KeyStatesMasks)(int)m.WParam & KeyStatesMasks.CONTROL) == KeyStatesMasks.CONTROL) &&
                        MultiSelect)
                    {
                        if (_SelectionMark.Parent == item.Parent &&
                            ((KeyStatesMasks)(int)m.WParam & KeyStatesMasks.SHIFT) == KeyStatesMasks.SHIFT)
                        {
                            _Updating = true;
                            SetSelectedItemsRange(item, _SelectionMark);
                            // Prevent all item at the wrong level of being selected
                            m.WParam = (IntPtr)KeyStatesMasks.CONTROL;
                            base.WndProc(ref m);
                            item.Selected = true;
                            _Updating = false;
                            DrawSelectedItemsFocusCues();
                            return;
                        }
                    }
                    break;

                #endregion

                #region LButtonDoubleClick

                // Disable this notification to remove the auto-check when
                // the user double-click on an item and append the expand / collapse function
                case WindowMessages.LBUTTONDBLCLK:
                    _LastDoubleClick = DateTime.Now;
                    if (FocusedItem != null)
                    {
                        item = FocusedItem;
                        bool doExpColl = false;
                        switch (ExpandMethod)
                        {
                            case TreeListViewExpandMethod.IconDbleClick:
                                rec = item.GetBounds(ItemBoundsPortion.Icon);
                                if (rec.Contains(PointToClient(MousePosition))) doExpColl = true;
                                break;
                            case TreeListViewExpandMethod.ItemOnlyDbleClick:
                                rec = item.GetBounds(ItemBoundsPortion.ItemOnly);
                                if (rec.Contains(PointToClient(MousePosition))) doExpColl = true;
                                break;
                            case TreeListViewExpandMethod.EntireItemDbleClick:
                                rec = item.GetBounds(ItemBoundsPortion.Entire);
                                if (rec.Contains(PointToClient(MousePosition))) doExpColl = true;
                                break;
                            default:
                                break;
                        }
                        if (doExpColl)
                        {
                            _DblClickTime = DateTime.Now;
                            Cursor = Cursors.WaitCursor;
                            BeginUpdate();
                            if (item.IsExpanded) item.Collapse();
                            else item.Expand();
                            EndUpdate();
                            Cursor = Cursors.Default;
                        }
                    }
                    OnDoubleClick(new EventArgs());
                    return;

                #endregion

                #region MouseMove

                case WindowMessages.MOUSEMOVE:
                    if ((MouseButtons & MouseButtons.Left) != MouseButtons.Left && HasMarquee)
                        _HasMarquee = false;
                    break;

                #endregion

                #region UniChar, Char, KeyDown

                case WindowMessages.UNICHAR:
                case WindowMessages.CHAR:
                    CharPressed((char)m.WParam);
                    return;
                case WindowMessages.KEYDOWN:
                    OnKeyDown(new KeyEventArgs((Keys)(int)m.WParam));
                    return;

                #endregion

                #region Paint

                case WindowMessages.PAINT:
                    if (InEdit && EditedItem.Item != null)
                    {
                        System.Win32.RECT rect = new System.Win32.RECT(EditedItem.Item.GetBounds(ItemBoundsPortion.Entire));
                        NativeMethods.ValidateRect(Handle, ref rect);
                    }
                    base.WndProc(ref m);
                    //DrawIntermediateStateItems();
                    //DrawSelectedItemsFocusCues();
                    return;

                #endregion

                #region VerticalScroll, HorizontalScroll, EnsureVisible

                case WindowMessages.VSCROLL:
                case WindowMessages.HSCROLL:
                case (WindowMessages)ListViewMessages.ENSUREVISIBLE:
                    if (!Scrollable)
                    {
                        m.Result = (IntPtr)0;
                        return;
                    }
                    break;

                #endregion
            }
            base.WndProc(ref m);
        }

        #region KeyFunction

        #region OnKeyDown

        /// <summary>
        /// Raises the KeyDown event
        /// </summary>
        /// <param name="e"></param>
        protected override void OnKeyDown(KeyEventArgs e)
        {
            Keys key = e.KeyCode;
            if (FocusedItem == null)
            {
                if (base.Items.Count > 0 && (key == Keys.Down || key == Keys.Up || key == Keys.Left || key == Keys.Right))
                {
                    base.Items[0].Selected = true;
                    base.Items[0].Focused = true;
                    base.Items[0].EnsureVisible();
                }
                base.OnKeyDown(e);
                return;
            }
            TreeListViewItem item = FocusedItem;
            switch (key)
            {
                case Keys.Down:
                    if (item.NextVisibleItem != null)
                    {
                        TreeListViewItem nextitem = item.NextVisibleItem;
                        if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift &&
                            MultiSelect)
                        {
                            if (item.Parent != nextitem.Parent && item.Selected)
                            {
                                while ((nextitem = nextitem.NextVisibleItem) != null)
                                {
                                    if (nextitem.Parent == item.Parent)
                                    {
                                        break;
                                    }
                                }
                            }
                            if (nextitem != null)
                            {
                                SetSelectedItemsRange(_SelectionMark, nextitem);
                            }
                            else
                            {
                                nextitem = item.NextVisibleItem;
                            }
                        }
                        else if ((Control.ModifierKeys & Keys.Control) != Keys.Control)
                        {
                            SetSelectedItemsRange(nextitem, nextitem);
                            _SelectionMark = nextitem;
                        }
                        nextitem.Focused = true;
                        nextitem.EnsureVisible();
                    }
                    break;
                case Keys.Up:
                    if (item.PrevVisibleItem != null)
                    {
                        TreeListViewItem previtem = item.PrevVisibleItem;
                        if ((Control.ModifierKeys & Keys.Shift) == Keys.Shift && MultiSelect)
                        {
                            if (item.Parent != previtem.Parent && item.Selected)
                            {
                                while ((previtem = previtem.PrevVisibleItem) != null)
                                {
                                    if (previtem.Parent == item.Parent)
                                    {
                                        break;
                                    }
                                }
                            }
                            if (previtem != null)
                            {
                                SetSelectedItemsRange(_SelectionMark, previtem);
                            }
                            else
                            {
                                previtem = item.PrevVisibleItem;
                            }
                        }
                        else if ((Control.ModifierKeys & Keys.Control) != Keys.Control)
                        {
                            SetSelectedItemsRange(previtem, previtem);
                            _SelectionMark = previtem;
                        }
                        previtem.Focused = true;
                        previtem.EnsureVisible();
                    }
                    break;
                case Keys.Enter:
                    base.SelectedItems.Clear();
                    if (item.IsExpanded) item.Collapse();
                    else item.Expand();
                    item.Selected = true;
                    item.EnsureVisible();
                    break;
                case Keys.Left:
                    if (item.IsExpanded)
                    {
                        base.SelectedItems.Clear();
                        item.Selected = true;
                        item.Collapse();
                        item.EnsureVisible();
                    }
                    else if (item.Parent != null)
                    {
                        base.SelectedItems.Clear();
                        item.Parent.Selected = true;
                        item.Parent.Focused = true;
                        item.Parent.EnsureVisible();
                    }
                    break;
                case Keys.Right:
                    if (item.Items.Count == 0) break;
                    if (!item.IsExpanded)
                    {
                        base.SelectedItems.Clear();
                        item.Selected = true;
                        item.Expand();
                        item.EnsureVisible();
                    }
                    else
                    {
                        base.SelectedItems.Clear();
                        item.Items[item.Items.Count - 1].Selected = true;
                        item.Items[item.Items.Count - 1].Focused = true;
                        item.Items[item.Items.Count - 1].EnsureVisible();
                    }
                    break;
                case Keys.Space:
                    if (base.CheckBoxes) item.Checked = !item.Checked;
                    break;
            }
            base.OnKeyDown(e);
        }

        #endregion

        #region CharPressed

        private void CharPressed(char character)
        {
            string begin = character.ToString().ToUpper();
            if (FocusedItem == null)
            {
                return;
            }
            TreeListViewItem item = FocusedItem;
            base.SelectedItems.Clear();
            item.Selected = true;
            // Select an item begining with the specified character
            if ((begin.CompareTo("A") >= 0 && begin.CompareTo("Z") <= 0) || begin == " ")
            {
                // Get the collection in wich the item is
                TreeListViewItemCollection collection = item.Parent == null ? this.Items : item.Parent.Items;
                bool founded = false;
                // Search in the next items
                for (int i = collection.GetIndexOf(item) + 1; i < collection.Count; i++)
                {
                    if (collection[i].Text.ToUpper().StartsWith(begin))
                    {
                        collection[i].Selected = true;
                        collection[i].Focused = true;
                        collection[i].EnsureVisible();
                        founded = true;
                        break;
                    }
                }
                // Search in the previous items
                if (!founded)
                {
                    for (int i = 0; i < collection.GetIndexOf(item); i++)
                    {
                        if (collection[i].Text.ToUpper().StartsWith(begin))
                        {
                            collection[i].Selected = true;
                            collection[i].Focused = true;
                            collection[i].EnsureVisible();
                            founded = true;
                            break;
                        }
                    }
                }
            }
        }

        #endregion

        #endregion

        #endregion

        #region Draw

        #region CustomDraw

        private void CustomDraw(ref Message m)
        {
            int row, column;
            bool selected;
            unsafe
            {
                NMLVCUSTOMDRAW* nmlvcd = (NMLVCUSTOMDRAW*)m.LParam.ToPointer();
                switch ((CustomDrawDrawStateFlags)nmlvcd->nmcd.dwDrawStage)
                {
                    //PrePaint
                    case CustomDrawDrawStateFlags.PREPAINT:
                        m.Result = (IntPtr)CustomDrawReturnFlags.NOTIFYITEMDRAW;
                        break;

                    //ItemPrePaint
                    case CustomDrawDrawStateFlags.ITEMPREPAINT:
                        m.Result = (IntPtr)CustomDrawReturnFlags.NOTIFYSUBITEMDRAW;
                        break;

                    //ItemPrePaint, SubItem
                    case CustomDrawDrawStateFlags.ITEMPREPAINT | CustomDrawDrawStateFlags.SUBITEM:
                        row = (int)nmlvcd->nmcd.dwItemSpec;
                        column = (int)nmlvcd->iSubItem;
                        selected = base.Items[row].Selected;// && this.Focused;
                        TreeListViewItem item = GetTreeListViewItemFromIndex(row);
                        if (selected && _UseXPHighLightStyle)
                        {
                            Color color = Focused ? ColorUtil.VSNetSelectionColor : ColorUtil.VSNetSelectionUnfocusedColor;
                            if (HideSelection && !Focused)
                            {
                                color = BackColor;
                            }
                            if (FullRowSelect || column == 0)
                            {
                                nmlvcd->clrTextBk = (int)ColorUtil.RGB(color.R, color.G, color.B);
                            }
                            nmlvcd->nmcd.uItemState &= ~(uint)CustomDrawItemStateFlags.SELECTED;
                            if (column == 0)
                            {
                                item.DrawFocusCues();
                            }
                        }
                        if (column == 0)
                        {
                            item.DrawIntermediateState();
                            item.DrawPlusMinusLines();
                            item.DrawPlusMinus();
                        }
                        m.Result = (IntPtr)CustomDrawReturnFlags.NEWFONT;
                        break;
                }
            }
        }

        #endregion

        #region Draw Items Parts

        internal void DrawIntermediateStateItems()
        {
            if (CheckBoxes != CheckBoxesTypes.Recursive) return;
            if (_Updating) return;
            TreeListViewItemCollection items = GetVisibleItems();
            using (Graphics g = Graphics.FromHwnd(Handle))
            {
                foreach (TreeListViewItem item in items)
                {
                    item.DrawIntermediateState(g);
                }
            }
        }

        internal void DrawSelectedItemsFocusCues()
        {
            if (_Updating) return;
            if ((HideSelection && !Focused) || !_UseXPHighLightStyle) return;

            SelectedTreeListViewItemCollection items = SelectedItems;
            if (FocusedItem != null && Focused)
            {
                FocusedItem.DrawFocusCues();
            }
            foreach (TreeListViewItem temp in items)
            {
                temp.DrawFocusCues();
            }
        }

        internal void DrawPlusMinusItems()
        {
            if (_Updating) return;

            using (Graphics g = Graphics.FromHwnd(Handle))
            {
                TreeListViewItemCollection items = GetVisibleItems();
                foreach (TreeListViewItem item in items)
                {
                    item.DrawPlusMinus(g);
                }
            }
        }

        internal void DrawPlusMinusItemsLines()
        {
            if (_Updating) return;

            using (Graphics g = Graphics.FromHwnd(Handle))
            {
                TreeListViewItemCollection items = GetVisibleItems();
                foreach (TreeListViewItem item in items)
                {
                    item.DrawPlusMinusLines(g);
                }
            }
        }

        #endregion

        protected override void OnDrawFirstSubItem(DrawListViewSubItemEventArgs e, Graphics g)
        {
            //base.OnDrawFirstSubItem(e, g);
            if (e.ColumnIndex > 0)
            {
                return;
            }
            GDIHelper.InitializeGraphics(g);
            TreeListViewItem item = e.Item as TreeListViewItem;
            int margin = 18;
            Rectangle rect = e.Bounds;
            Image img = null;
            Size imgSize = Size.Empty;
            Rectangle checkBoxRect = new Rectangle(rect.X, rect.Y, 0, 0), flagRect;
            Size flagSize = new System.Drawing.Size(12, 12);
            int offset = 2;
            flagRect = new Rectangle(new Point(offset * 2, rect.Top + (rect.Height - flagSize.Height) / 2), flagSize);
            flagRect.X += (item.Level) * margin;
            Rectangle imgRect = checkBoxRect;
            Rectangle textRect = rect; textRect.X = flagRect.Right;
            if (item.Parent != null)
            {
                Point p1, p2, p3;
                p1 = new Point(flagRect.X + flagSize.Width / 2 - margin, item.Parent.Bounds.Bottom - offset);
                p2 = new Point(item.Items.Count <= 0 ? flagRect.X + flagSize.Width : flagRect.X - offset, rect.Top + rect.Height / 2);
                p3 = new Point(p1.X, p2.Y);
                Color c = Color.FromArgb(46, 117, 35);
                using (Pen pen = new Pen(this._PlusMinusLineColor, 1))
                {
                    if (this._PlusMinusLinePattern > 0)
                    {
                        pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Custom;
                        pen.DashPattern = new float[] { 3f, this._PlusMinusLinePattern };
                    }
                    g.DrawLines(pen, new Point[] { p1, p3, p2 });
                }

                imgRect.X += margin + offset;
                textRect.X += margin + offset;
                textRect.Width -= offset + offset * 2;
            }
            if (item.Items.Count > 0)
            {
                GDIHelper.DrawImage(g, flagRect, item.IsExpanded ? Properties.Resources.Collapse1 : Properties.Resources.Expand1, flagSize);
                imgRect.X += flagRect.Width + offset;
                textRect.X += flagRect.Width + offset;
                textRect.Width -= flagRect.Width + offset;
            }

            if (e.Item.ListView.CheckBoxes)
            {
                checkBoxRect.X += offset * 2 + flagRect.Right;
                checkBoxRect.Y = rect.Top + (rect.Height - this.CheckBoxSize.Height) / 2;
                checkBoxRect.Width = this.CheckBoxSize.Width;
                checkBoxRect.Height = this.CheckBoxSize.Height;
                imgRect.X = checkBoxRect.Right;
                textRect.X = checkBoxRect.Right;
                textRect.Width -= this.CheckBoxSize.Width - offset * 2;
                GDIHelper.DrawCheckBox(g, new RoundRectangle(checkBoxRect, 1));
                switch (item.CheckStatus)
                {
                    case System.Windows.Forms.CheckState.Checked:
                        GDIHelper.DrawCheckedStateByImage(g, checkBoxRect);
                        break;
                    case System.Windows.Forms.CheckState.Indeterminate:
                        Rectangle innerRect = checkBoxRect;
                        innerRect.Inflate(-3, -3);
                        Color cc = Color.FromArgb(46, 117, 35);
                        GDIHelper.FillRectangle(g, new RoundRectangle(innerRect, 1), cc);
                        break;
                }
            }
            if (e.Item.ImageList != null && e.Item.ImageIndex >= 0)
            {
                img = e.Item.ImageList.Images[e.Item.ImageIndex];
                imgSize = e.Item.ImageList.ImageSize;
                imgRect.X += offset * 3;
                imgRect.Y = rect.Y + offset;
                int width = rect.Height - offset * 2;
                imgRect.Width = width;
                imgRect.Height = width;
                textRect.X = imgRect.Right;
                textRect.Width -= width - offset * 2;
                GDIHelper.DrawImage(g, imgRect, img, imgSize);
            }

            textRect.X += offset;
            textRect.Width -= offset * 2;
            TextFormatFlags flags = GetFormatFlags(e.Header.TextAlign);
            Color fc = (e.ItemState & System.Windows.Forms.ListViewItemStates.Selected) == System.Windows.Forms.ListViewItemStates.Selected ?
                Color.White : e.SubItem.ForeColor;
            TextRenderer.DrawText(g, e.SubItem.Text, this.Font, textRect, fc, flags);
        }

        #endregion

        #region Functions

        #region SetSelectedItemsRange

        private void SetSelectedItemsRange(TreeListViewItem item1, TreeListViewItem item2)
        {
            if (InvokeRequired)
            {
                throw (new Exception("Invoke required"));
            }
            if (item1 == null || item2 == null) return;
            if (!item1.Visible || !item2.Visible) return;
            if (item1.Parent != item2.Parent) return;
            TreeListViewItemCollection items = item1.Container;
            int index1 = items.GetIndexOf(item1);
            int index2 = items.GetIndexOf(item2);
            ListViewItem[] selItems = new ListViewItem[base.SelectedItems.Count];
            base.SelectedItems.CopyTo(selItems, 0);
            foreach (ListViewItem selItem in selItems)
            {
                int selItemIndex = items.GetIndexOf((TreeListViewItem)selItem);
                if (selItemIndex < Math.Min(index1, index2) || selItemIndex > Math.Max(index1, index2))
                {
                    selItem.Selected = false;
                }
            }
            for (int i = Math.Min(index1, index2); i <= Math.Max(index1, index2); i++)
            {
                if (!items[i].Selected)
                {
                    items[i].Selected = true;
                }
            }
        }

        #endregion

        #region ExpandAll / CollapseAll

        public void ExpandAll()
        {
            if (InvokeRequired)
            {
                throw (new Exception("Invoke required"));
            }
            BeginUpdate();
            foreach (TreeListViewItem item in Items)
            {
                item.ExpandAllInternal();
            }
            EndUpdate();
        }

        public void CollapseAll()
        {
            if (InvokeRequired)
            {
                throw (new Exception("Invoke required"));
            }
            BeginUpdate();
            foreach (TreeListViewItem item in Items)
            {
                item.CollapseAllInternal();
            }
            EndUpdate();
        }

        #endregion

        #region ExitEdit

        internal void ExitEdit(bool cancel, string text)
        {
            if (!InEdit || EditedItem.Item == null) return;
            // Mouse position
            Point point = EditedItem.Item != null ? EditedItem.Item.GetBounds(TreeListViewItemBoundsPortion.Icon).Location : new Point(0, 0);
            point.Offset(1, 1);
            EditItemInformations editedItem = EditedItem;

            Message m = Message.Create(Handle, (int)WindowMessages.LBUTTONDOWN, (IntPtr)1, (IntPtr)((point.Y << 16) + point.X));
            _SkipMouseDownEvent = true;
            base.WndProc(ref m);
            _SkipMouseDownEvent = false;
            if (!cancel)
            {
                TreeListViewLabelEditEventArgs e = new TreeListViewLabelEditEventArgs(EditedItem.Item, EditedItem.ColumnIndex, text);
                OnAfterLabelEdit(e);
                if (!e.Cancel)
                {
                    editedItem.Item.SubItems[editedItem.ColumnIndex].Text = text;
                }
            }
            _InEdit = false;
            _EditedItem = new EditItemInformations(null, 0, "");
        }

        #endregion

        #region GetItemRect

        /// <summary>
        /// Retrieves the specified portion of the bounding rectangle for a specific item within the list view control
        /// </summary>
        /// <param name="index">The zero-based index of the item within the ListView.ListViewItemCollection whose bounding rectangle you want to return</param>
        /// <param name="portion">One of the TreeListViewItemBoundsPortion values that represents a portion of the TreeListViewItem for which to retrieve the bounding rectangle</param>
        /// <returns>A Rectangle that represents the bounding rectangle for the specified portion of the specified TreeListViewItem</returns>
        public Rectangle GetItemRect(int index, TreeListViewItemBoundsPortion portion)
        {
            if (index >= base.Items.Count || index < 0)
            {
                throw new Exception("Out of range exception");
            }
            TreeListViewItem item = (TreeListViewItem)base.Items[index];
            return item.GetBounds(portion);
        }

        #endregion

        #region KillFocus

        /// <summary>
        /// Kill the focus of the control
        /// </summary>
        public void KillFocus()
        {
            NativeMethods.SendMessage(Handle, (int)WindowMessages.KILLFOCUS, IntPtr.Zero, IntPtr.Zero);
        }

        #endregion

        #region OnItemCheck

        /// <summary>
        /// Raises the ItemCheck event
        /// </summary>
        /// <param name="e">An ItemCheckEventArgs that contains the event data</param>
        protected override void OnItemCheck(ItemCheckEventArgs e)
        {
            base.OnItemCheck(e);
            ListView.ListViewItemCollection baseItems = base.Items;
            if (e.Index >= base.Items.Count || e.Index < 0)
                return;
            TreeListViewItem item = (TreeListViewItem)base.Items[e.Index];
            if (item == null) return;
            if (this.CheckDirection == CheckDirection.None) return;
            CheckDirection oldDirection = CheckDirection;

            TreeListViewItem parentItem = item.Parent;
            if (parentItem != null && (oldDirection & CheckDirection.Upwards) == CheckDirection.Upwards)
            {
                CheckDirection = CheckDirection.Upwards;
                while (parentItem != null)
                {
                    if (e.NewValue == CheckState.Checked)
                    {
                        if (!parentItem.Checked)
                        {
                            parentItem.Checked = true;
                            break;
                        }
                        else
                        {
                            bool allChecked = true;
                            foreach (TreeListViewItem childItem in parentItem.Items)
                            {
                                if (childItem == item) continue;
                                if (!childItem.Checked)
                                {
                                    allChecked = false;
                                    break;
                                }
                            }
                            if (allChecked) parentItem.Redraw();
                        }
                    }
                    else
                    {
                        bool allUnChecked = true;
                        foreach (TreeListViewItem childItem in parentItem.Items)
                        {
                            if (childItem == item) continue;
                            if (childItem.Checked)
                            {
                                allUnChecked = false;
                                break;
                            }
                        }
                        if (allUnChecked && parentItem.Checked)
                        {
                            parentItem.Checked = false;
                            break;
                        }
                    }
                    parentItem = parentItem.Parent;
                }
            }

            if ((oldDirection & CheckDirection.Downwards) == CheckDirection.Downwards)
            {
                CheckDirection = CheckDirection.Downwards;
                foreach (TreeListViewItem childItem in item.Items)
                    childItem.Checked = e.NewValue == CheckState.Checked;
            }
            CheckDirection = oldDirection;
        }

        #endregion

        #region OnColumnClick 实现排序及排序的标识绘制
        /// <summary>
        /// Raises the ColumnClick event
        /// </summary>
        /// <param name="e">A ColumnClickEventArgs that contains the event data</param>
        protected override void OnColumnClick(System.Windows.Forms.ColumnClickEventArgs e)
        {
            base.OnColumnClick(e);
            Cursor = Cursors.WaitCursor;
            ListViewItem[] selItems = new ListViewItem[base.SelectedItems.Count];
            base.SelectedItems.CopyTo(selItems, 0);

            // Must set ListView.checkDirection to CheckDirection.None. 
            // Forbid recursively checking. 
            CheckDirection oldDirection = CheckDirection;
            CheckDirection = CheckDirection.None;
            BeginUpdate();
            if (Comparer.Column == e.Column)
                Sorting = (Sorting == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending);
            else
            {
                Comparer.Column = e.Column;
                Items.SortOrderRecursivelyWithoutSort = SortOrder.Ascending;
                try { Items.Sort(true); }
                catch { }
            }

            if (FocusedItem != null) FocusedItem.EnsureVisible();
            foreach (ListViewItem item in selItems)
                if (item.Index > -1) item.Selected = true;
            EndUpdate();
            // Reset ListView.checkDirection
            CheckDirection = oldDirection;
            Cursor = Cursors.Default;
            this.Invalidate(new Rectangle(Point.Empty, new Size(this.Width, 20)), true);
        }

        protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e)
        {
            base.OnDrawColumnHeader(e);
            if (Comparer.Column == e.ColumnIndex)
            {
                Rectangle rect = e.Bounds;
                int offset = 3;
                Size arrowSize = new System.Drawing.Size(8, 6);
                Rectangle sortRect = new Rectangle(rect.Right - offset - arrowSize.Width,
                    rect.Y + (rect.Height - arrowSize.Height) / 2,
                    arrowSize.Width, arrowSize.Height);
                Graphics g = e.Graphics;
                GDIHelper.InitializeGraphics(g);
                Color c = Color.FromArgb(46, 117, 35);
                switch (this.Sorting)
                {
                    case SortOrder.Ascending:
                        GDIHelper.DrawArrow(g, ArrowDirection.Up, sortRect, arrowSize, 1.5f, c);
                        break;
                    case SortOrder.Descending:
                        GDIHelper.DrawArrow(g, ArrowDirection.Down, sortRect, arrowSize, 1.5f, c);
                        break;
                }
            }
        }

        #endregion

        #region OnVisibleChanged
        /// <summary>
        /// Raises the VisibleChanged event
        /// </summary>
        /// <param name="e"></param>
        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            if (base.SmallImageList != _SmallImagList)
                base.SmallImageList = _SmallImagList;
            VisChanged();
        }
        internal void VisChanged()
        {
            if (!Visible) return;
            BeginUpdate();
            try
            {
                foreach (TreeListViewItem item in this.Items)
                    item.RefreshIndentation(true);
            }
            catch { }
            if (FocusedItem != null) FocusedItem.EnsureVisible();
            EndUpdate();
        }
        #endregion

        #region GetItemAt

        /// <summary>
        /// Gets an item at the specified coordinates
        /// </summary>
        /// <param name="p">Mouse position</param>
        /// <returns></returns>
        public TreeListViewItem GetItemAt(Point p)
        {
            return GetItemAt(p.X, p.Y);
        }

        /// <summary>
        /// Gets an item at the specified coordinates (fullrow)
        /// </summary>
        /// <param name="p">Mouse position</param>
        /// <returns></returns>
        public TreeListViewItem GetItemAtFullRow(Point p)
        {
            if (FullRowSelect)
            {
                return GetItemAt(p);
            }
            TreeListViewItemCollection items = GetVisibleItems();
            foreach (TreeListViewItem item in items)
            {
                if (item.GetBounds(TreeListViewItemBoundsPortion.Entire).Contains(p))
                {
                    return item;
                }
            }
            return null;
        }

        /// <summary>
        /// Gets an item at the specified coordinates.
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public new TreeListViewItem GetItemAt(int x, int y)
        {
            return (TreeListViewItem)base.GetItemAt(x, y);
        }

        #endregion

        #region GetTreeListViewItemFromIndex

        /// <summary>
        /// Gets the TreeListViewItem from the ListView index of the item
        /// </summary>
        /// <param name="index">Index of the Item</param>
        /// <returns></returns>
        public TreeListViewItem GetTreeListViewItemFromIndex(int index)
        {
            if (base.Items.Count < index + 1)
            {
                return null;
            }
            return (TreeListViewItem)base.Items[index];
        }

        #endregion

        #region Sort

        /// <summary>
        /// Not supported (use items.Sort)
        /// </summary>
        public new void Sort()
        {
            if (InvokeRequired)
            {
                throw new Exception("Invoke required");
            }
            Items.Sort(true);
        }

        #endregion

        #region Dispose

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

        #endregion

        #region BeginUpdate / EndUpdate

        /// <summary>
        /// Prevents the control from drawing until the EndUpdate method is called
        /// </summary>
        public new void BeginUpdate()
        {
            _Updating = true;
            base.BeginUpdate();
        }

        /// <summary>
        /// Resumes drawing of the list view control after drawing is suspended by the BeginUpdate method
        /// </summary>
        public new void EndUpdate()
        {
            _Updating = false;
            base.EndUpdate();
        }

        #endregion

        #endregion

        #region Column Order

        /// <summary>
        /// Get the index of the specified column from its physical position
        /// </summary>
        /// <param name="columnorder"></param>
        /// <returns></returns>
        public int GetColumnIndex(int columnOrder)
        {
            if (columnOrder < 0 || columnOrder > Columns.Count - 1) return (-1);
            return NativeMethods.SendMessage(Handle, (int)HeaderControlMessages.ORDERTOINDEX, columnOrder, 0);
        }

        /// <summary>
        /// Gets the order of a specified column
        /// </summary>
        /// <param name="columnindex"></param>
        /// <returns></returns>
        public int GetColumnOrder(int columnIndex)
        {
            if (this.Columns.Count == 0)
            {
                return -1;
            }
            if (columnIndex < 0 || columnIndex > this.Columns.Count - 1)
            {
                return -1;
            }
            IntPtr[] colorderarray = new IntPtr[this.Columns.Count];
            SendMessage(this.Handle, (int)ListViewMessages.GETCOLUMNORDERARRAY, (IntPtr)this.Columns.Count, ref colorderarray[0]);
            return (int)colorderarray[columnIndex];
        }

        /// <summary>
        /// Gets the columns order
        /// </summary>
        /// <returns>Example {3,1,4,2}</returns>
        public int[] GetColumnsOrder()
        {
            if (this.Columns.Count == 0) return new int[] { };
            IntPtr[] columnOrderArray = new IntPtr[this.Columns.Count];
            try
            {
                SendMessage(this.Handle, (int)ListViewMessages.GETCOLUMNORDERARRAY, (IntPtr)this.Columns.Count, ref columnOrderArray[0]);
            }
            catch
            {
            }
            int[] columnOrderArrayInt = new int[this.Columns.Count];
            for (int i = 0; i < this.Columns.Count; i++)
            {
                columnOrderArrayInt[i] = (int)columnOrderArray[i];
            }
            return columnOrderArrayInt;
        }

        /// <summary>
        /// Indicates the column order (for example : {0,1,3,2})
        /// </summary>
        /// <param name="colorderarray"></param>
        public void SetColumnsOrder(int[] columnOrderArray)
        {
            if (this.Columns.Count == 0)
            {
                return;
            }
            if (columnOrderArray.Length != this.Columns.Count)
            {
                return;
            }
            if (columnOrderArray[0] != 0)
            {
                return;
            }
            IntPtr[] columnOrderArrayIntptr = new IntPtr[this.Columns.Count];
            for (int i = 0; i < this.Columns.Count; i++)
            {
                columnOrderArrayIntptr[i] = (IntPtr)columnOrderArray[i];
            }
            try
            {
                SendMessage(this.Handle, (int)ListViewMessages.SETCOLUMNORDERARRAY, (IntPtr)this.Columns.Count, ref columnOrderArrayIntptr[0]);
            }
            catch { }
            Refresh();
        }

        private void InnerScroll()
        {
            while (MouseButtons == MouseButtons.Middle)
            {
                int dx = MousePosition.Y - _MouseScrollPosition.Y;
                int dy = MousePosition.Y - _MouseScrollPosition.Y;
                Scroll(dx, dy);
                System.Threading.Thread.Sleep(100);
            }
            Cursor = Cursors.Default;
        }

        /// <summary>
        /// Scrolls the control
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public void Scroll(int x, int y)
        {
            NativeMethods.SendMessage(Handle, (int)ListViewMessages.SCROLL, x, y);
        }

        /// <summary>
        /// Indicates the column order (for example : "3142")
        /// </summary>
        /// <param name="colorder"></param>
        public void SetColumnsOrder(string columnsOrder)
        {
            if (columnsOrder == null) return;
            int[] columnsOrderArray = new int[columnsOrder.Length];
            for (int i = 0; i < columnsOrder.Length; i++)
            {
                columnsOrderArray[i] = int.Parse(new String(columnsOrder[i], 1));
            }
            SetColumnsOrder(columnsOrderArray);
        }

        #endregion

        #region Item Region

        /// <summary>
        /// Gets the items that are visible in the TreeListView
        /// </summary>
        /// <returns>A collection of items</returns>
        public TreeListViewItemCollection GetVisibleItems()
        {
            TreeListViewItemCollection visibleItems = new TreeListViewItemCollection();
            if (base.Items.Count == 0)
            {
                return visibleItems;
            }

            int firstItemIndex = TopItem.Index;
            int itemsPerPageCount = NativeMethods.SendMessage(Handle, (int)ListViewMessages.GETITEMCOUNT, IntPtr.Zero, IntPtr.Zero);
            int lastVisibleItemIndex = firstItemIndex + itemsPerPageCount > base.Items.Count ?
                base.Items.Count : firstItemIndex + itemsPerPageCount;
            for (int i = firstItemIndex; i < lastVisibleItemIndex; i++)
            {
                visibleItems.Add((TreeListViewItem)base.Items[i]);
            }
            return visibleItems;
        }

        /// <summary>
        /// Gets the column at the specified position
        /// </summary>
        /// <param name="p">Point in client coordinates</param>
        /// <returns>The nul zero based index of the column (-1 if failed)</returns>
        public int GetColumnAt(Point p)
        {
            LVHITTESTINFO hittest = new LVHITTESTINFO();
            hittest.pt = new POINTAPI(PointToClient(MousePosition));
            SendMessage(Handle, (Int32)ListViewMessages.SUBITEMHITTEST, 0, ref hittest);
            return hittest.iSubItem;
        }

        /// <summary>
        /// Get SubItem rectangle
        /// </summary>
        /// <param name="item"></param>
        /// <param name="column"></param>
        /// <returns></returns>
        public Rectangle GetSubItemRect(TreeListViewItem item, int column)
        {
            ListViewItem lvitem = (ListViewItem)item;
            return GetSubItemRect(lvitem.Index, column);
        }

        /// <summary>
        /// Get SubItem rectangle
        /// </summary>
        /// <param name="row"></param>
        /// <param name="col"></param>
        /// <returns></returns>
        public Rectangle GetSubItemRect(int row, int col)
        {
            RECT rc = new RECT();
            rc.top = col;
            rc.left = (int)ListViewSubItemPortion.BOUNDS;
            SendMessage(Handle, (int)ListViewMessages.GETSUBITEMRECT, row, ref rc);
            if (col == 0)
            {
                // The LVM_GETSUBITEMRECT message does not give us the rectangle for the first subitem
                // since it is not considered a subitem
                // obtain the rectangle for the header control and calculate from there
                Rectangle headerRect = GetHeaderItemRect(col);
                return new Rectangle((int)rc.left, (int)rc.top, (int)headerRect.Width, (int)(rc.bottom - rc.top));
            }
            return new Rectangle((int)rc.left, (int)rc.top, (int)(rc.right - rc.left), (int)(rc.bottom - rc.top));
        }

        /// <summary>
        /// Get HeaderItem text
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public string GetHeaderItemText(int index)
        {
            HDITEM hdi = new HDITEM();
            hdi.mask = (int)HeaderItemFlags.TEXT;
            hdi.cchTextMax = 255;
            hdi.pszText = Marshal.AllocHGlobal(255);
            SendMessage(Handle, HeaderControlMessages.GETITEMW, index, ref hdi);
            return Marshal.PtrToStringAuto(hdi.pszText);
        }
        /// <summary>
        /// Get HeaderItem rect
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        protected Rectangle GetHeaderItemRect(int index)
        {
            RECT rc = new RECT();
            IntPtr header = NativeMethods.GetDlgItem(Handle, 0);
            SendMessage(header, (int)HeaderControlMessages.GETITEMRECT, index, ref rc);
            return new Rectangle((int)rc.left, (int)rc.top, (int)(rc.right - rc.left), (int)(rc.bottom - rc.top));
        }
        /// <summary>
        /// Get row rect
        /// </summary>
        /// <param name="row"></param>
        /// <returns></returns>
        public Rectangle GetRowRect(int row)
        {
            RECT rc = new RECT();
            rc.top = 0;
            rc.left = (int)ListViewSubItemPortion.BOUNDS;
            SendMessage(Handle, (int)ListViewMessages.GETSUBITEMRECT, row, ref rc);
            return new Rectangle((int)rc.left, (int)rc.top, (int)(rc.right - rc.left), (int)(rc.bottom - rc.top));
        }

        #endregion

        #region Component Designer generated code

        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(TreeListView));
            this.imageList1 = new System.Windows.Forms.ImageList(this.components);
            this.plusMinusImageList = new System.Windows.Forms.ImageList(this.components);
            this.SuspendLayout();
            // 
            // imageList1
            // 
            this.imageList1.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit;
            this.imageList1.ImageSize = new System.Drawing.Size(16, 16);
            this.imageList1.TransparentColor = System.Drawing.Color.Transparent;
            // 
            // plusMinusImageList
            // 
            this.plusMinusImageList.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("plusMinusImageList.ImageStream")));
            this.plusMinusImageList.TransparentColor = System.Drawing.Color.Transparent;
            this.plusMinusImageList.Images.SetKeyName(0, "");
            this.plusMinusImageList.Images.SetKeyName(1, "");
            // 
            // TreeListView
            // 
            this.FullRowSelect = true;
            this.View = System.Windows.Forms.View.Details;
            this.ResumeLayout(false);

        }

        #endregion

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
        DefaultValue(true),
        Browsable(true),
        Description("Gets or sets a value indicating whether a scroll bar is added to the control when there is not enough room to display all items")
        ]
        public new bool Scrollable
        {
            get { return _Scrollable; }
            set { _Scrollable = value; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether a check box appears next to each item in the control
        /// </summary>
        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
        DefaultValue(typeof(CheckBoxesTypes), "None"),
        Browsable(true),
        Description("Gets or sets a value indicating whether a check box appears next to each item in the control")
        ]
        public new CheckBoxesTypes CheckBoxes
        {
            get { return _CheckBoxes; }
            set
            {
                if (_CheckBoxes == value) return;
                _CheckBoxes = value;
                CheckDirection = value == CheckBoxesTypes.Recursive ? CheckDirection.All : CheckDirection.None;
                base.CheckBoxes = value == CheckBoxesTypes.None ? false : true;
                if (Created)
                {
                    Invalidate();
                }
            }
        }

        [
        Browsable(true),
        Description("Gets or sets a value indicating whether clicking an item selects all its subitems"),
        DefaultValue(true)
        ]
        public new bool FullRowSelect
        {
            get { return base.FullRowSelect; }
            set { base.FullRowSelect = value; }
        }

        [Browsable(false)]
        public new ImageList StateImageList
        {
            get { return base.StateImageList; }
            set { base.StateImageList = value; }
        }

        [Browsable(false)]
        public new ImageList LargeImageList
        {
            get { return base.LargeImageList; }
            set { base.LargeImageList = value; }
        }

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
        DefaultValue(null),
        Browsable(true),
        Description("Gets or sets the ImageList to use when displaying items as small icons in the control")
        ]
        public new ImageList SmallImageList
        {
            get { return _SmallImagList; }
            set { _SmallImagList = value; }
        }

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
        Browsable(true),
        Description("Get or Set the sort order"),
        DefaultValue(typeof(SortOrder), "Ascending")
        ]
        public new SortOrder Sorting
        {
            get { return _Sorting; }
            set
            {
                if (_Sorting == value) return;
                _Sorting = value;
                Items.SortOrderRecursively = value;
            }
        }

        [
        Browsable(true),
        DefaultValue(typeof(TreeListViewExpandMethod), "EntireItemDbleClick"),
        Description("Get or Set the expand method")]
        public TreeListViewExpandMethod ExpandMethod
        {
            get { return _ExpandMethod; }
            set { _ExpandMethod = value; }
        }

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        Browsable(false)
        ]
        public new View View
        {
            get { return base.View; }
            set { base.View = View.Details; }
        }

        /// <summary>
        /// Items of the TreeListView
        /// </summary>
        //		[Browsable(true),
        //		Editor(typeof(TreeListViewItemsEditor), typeof(System.Drawing.Design.UITypeEditor))]
        [Browsable(false)]
        [Description("Items of the TreeListView")]
        public new TreeListViewItemCollection Items
        {
            get { return _Items; }
        }

        [Browsable(false)]
        public new SelectedTreeListViewItemCollection SelectedItems
        {
            get { return new SelectedTreeListViewItemCollection(this); }
        }

        [Browsable(false)]
        public new TreeListViewItem[] CheckedItems
        {
            get { return (TreeListViewItem[])Invoke(new ItemArrayHandler(GetCheckedItems)); }
        }

        private TreeListViewItem[] GetCheckedItems()
        {
            if (InvokeRequired)
            {
                throw new Exception("Invoke required");
            }
            TreeListViewItemCollection items = new TreeListViewItemCollection();
            foreach (TreeListViewItem item in Items)
            {
                item.GetCheckedItems(ref items);
            }
            return (items.ToArray());
        }

        [Browsable(false)]
        public new TreeListViewItem FocusedItem
        {
            get { return (TreeListViewItem)base.FocusedItem; }
        }

        [Browsable(false)]
        public bool HasMarquee
        {
            get { return _HasMarquee; }
        }

        [Browsable(false)]
        public EditItemInformations EditedItem
        {
            get { return _EditedItem; }
        }

        [Browsable(false)]
        public bool InEdit
        {
            get { return _InEdit; }
        }

        [Browsable(false)]
        public int ItemsCount
        {
            get
            {
                TreeListViewItem[] items = _Items.ToArray();
                int count = items.Length;
                foreach (TreeListViewItem item in items) count += item.ChildrenCount;
                return count;
            }
        }

        [Browsable(false)]
        public ITreeListViewItemComparer Comparer
        {
            get { return (Items.Comparer); }
            set { Items.Comparer = value; }
        }

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
        DefaultValue(true),
        Browsable(true),
        Description("Gets or sets a value indicating whether plus-sign (+) and minus-sign (-) buttons are displayed next to TreeListView that contain child TreeListViews")
        ]
        public bool ShowPlusMinus
        {
            get { return _ShowPlusMinus; }
            set
            {
                if (_ShowPlusMinus == value) return;
                _ShowPlusMinus = value;
                if (Created) Invoke(new MethodInvoker(VisChanged));
            }
        }

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
        DefaultValue(typeof(Color), "DarkGray"),
        Browsable(true),
        Description("Gets or Sets the color of the lines if ShowPlusMinus property is enabled")
        ]
        public Color PlusMinusLineColor
        {
            get { return _PlusMinusLineColor; }
            set
            {
                _PlusMinusLineColor = value;
                if (Created)
                {
                    Invalidate();
                }
            }
        }

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
        DefaultValue(0),
        Browsable(true),
        Description("获取或者自定义线的样式，为0表示视线，否则为虚线的空白间隔，以像素为单位")
        ]
        public int PlusMinusLinePattern
        {
            get { return this._PlusMinusLinePattern; }
            set
            {
                this._PlusMinusLinePattern = value > 0 ? value : 0;
                if (Created)
                {
                    this.Invalidate();
                }
            }
        }

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
        DefaultValue(true),
        Browsable(true),
        Description("Gets or Sets whether the control draw XP-Style highlight color")
        ]
        public bool UseXPHighlightStyle
        {
            get { return _UseXPHighLightStyle; }
            set
            {
                _UseXPHighLightStyle = value;
                if (Created) Invalidate();
            }
        }

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Visible),
        DefaultValue("\\"),
        Browsable(true),
        Description("Gets or sets the delimiter string that the TreeListViewItem path uses")
        ]
        public string PathSeparator
        {
            get { return _PathSeparator; }
            set { _PathSeparator = value; }
        }

        [DllImport("user32.dll")]
        internal static extern bool SendMessage(IntPtr hWnd, int msg, IntPtr wParam, ref IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        internal static extern void SendMessage(IntPtr hWnd, int msg, int wParam, ref RECT lParam);

        [DllImport("user32.dll")]
        internal static extern int SendMessage(IntPtr hWnd, Int32 msg, Int32 wParam, ref LVHITTESTINFO lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        internal static extern int SendMessage(IntPtr hWnd, HeaderControlMessages msg, int wParam, ref HDITEM lParam);
    }
}
