Click here to Skip to main content
15,888,968 members
Articles / Desktop Programming / Windows Forms
Article

Extended ListView

Rate me:
Please Sign up or sign in to vote.
4.74/5 (52 votes)
13 Jun 20064 min read 505.8K   29.3K   266   114
An extended ListView control that can show multiple images on subitems, lets the user edit subitems with user-defined controls (also image-subitems), contains boolean subitems, and can sort columns by date, number, string, and image.

Sample Image - EXListView.gif

Introduction

There are many examples here on The Code Project that enhance the functionality of the ListView. I was looking for a way to display and edit multiple images on subitems and be able to sort the ListView by date, number, string, and images, but I wasn't able to find one that could do that. The subitems also had to be editable - either by a textbox, or by a user defined control. Finally, I wanted to be able to add controls to the subitems and provide some kind of "boolean" columns. The subitems that are in such a boolean column will be able to show two values - true or false - that can be represented by two images. If you set the Editable property to true, the user can click such a subitem and the value switches.

Background

Previously, you had to use the Win32 API to accomplish the above. Now, with version 2.0 of the .NET framework, this can be much easily done with the concept of ownerdraw. If the OwnerDraw property of a ListView is set to false, you can do all of the drawing of the ListView yourself. In this EXListView class, I use ownerdraw extensively. Although using the Win32 API is faster than using ownerdraw from the .NET framework, this ListView is still fast, even with 1000 items with subitems that contain multiple images.

Using the code

The code accompanying this article is the EXListView class, the EXComboBox class, and a simple form that uses these in a form. I added an executable, but you can easily compile it yourself with the command csc /t:winexe /r:System.Windows.Forms.dll EXListView.cs EXComboBox.cs MyForms.cs - the compiler csc.exe can be found on Windows XP in C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\.

Defining an instance and adding columns

If you have created an instance of the EXListView class (for example: EXListView exlstv = new EXListView()), you can begin adding columns. There are three different types of columns: EXColumnHeader, EXEditableColumnHeader (whose subitems can be edited by a default TextBox or a user defined control), and the EXBoolColumnHeader (whose subitems can only show true or false and can optionally be edited).

For example, to get a column header that can be edited by a default TextBox, you do:

C#
EXEditableColumnHeader editcol = 
                  new EXEditableColumnHeader("Movie");

If you want to specify a control by which the subitems can be edited, you do:

C#
// define a control to edit the subitems of this column
ComboBox cmbx = new ComboBox();
cmbx.Items.AddRange(new string[] {"1", "2", "3", "4"});
// define a columnheader whose subitems can be edited
EXEditableColumnHeader editcol = 
     new EXEditableColumnHeader("Position");
// add the combobox to the column
editcol.MyControl = cmbx;

A boolean column:

C#
EXBoolColumnHeader boolcol = new EXBoolColumnHeader("OK");
// if you want the users to be able to edit
// the boolean values, set the Editable property to true
boolcol.Editable = true;
// specify an image for each of the values
boolcol.TrueImage = Image.FromFile("true.png");
boolcol.FalseImage = Image.FromFile("false.png");

Add (sub)items to the EXListView

A regular ListViewItem:

C#
EXListViewItem lstvitem = new EXListViewItem("Pete");

Items and subitems that can show images have a property MyValue that can hold the real textual value of the (sub)item. This can be handy if you don't want to show text, but need some kind of value, for example, to insert into a database.

An item that can show only one image:

C#
EXImageListViewItem imglstvitem = new EXImageListViewItem();
imglstvitem.MyImage = Image.FromFile("Pete.jpg");
imglstvitem.MyValue = "Pete";

An item that can show multiple images:

C#
EXMultipleImagesListViewItem mimglstvitem = 
        new EXMultipleImagesListViewItem();
// define arraylist with all the images
ArrayList images = new ArrayList(new object[] 
          {Image.FromFile("Pete.jpg"), 
          Image.FromFile("man.png")});
mimglstvitem.MyImages = images;
imglstvitem.MyValue = "Pete the man";

The same way, you can add subitems to the EXListView. Please see the EXListView class for more information.

Use the EXComboBox to edit items with images

The source also contains an extended ComboBox class - the EXComboBox class: this is a combobox that can hold images. You can use this combobox to edit (sub)items with images in the EXListView.

C#
// create an EXListView
EXListView lstv = new EXListView();
// craete an EXComboBox
EXComboBox excmbx = new EXComboBox();
excmbx.MyHighlightBrush = Brushes.Goldenrod;
excmbx.ItemHeight = 20;
// add images to the combobox and the values
excmbx.Items.Add(new EXComboBox.EXImageItem(
       Image.FromFile("music.png"), "Music"));
excmbx.Items.Add(new EXComboBox.EXImageItem(
     Image.FromFile("comedy.png"), "Comedy"));
excmbx.Items.Add(new EXComboBox.EXMultipleImagesItem(
       new ArrayList(new object[] 
       {Image.FromFile("love.png"), 
       Image.FromFile("comedy.png")}), 
       "Romantic comedy"));
// add this combobox to the first columnheader
lstv.Columns.Add(new EXEditableColumnHeader("Genre", 
                                       excmbx, 60));

Add and remove images during runtime

If you want to add or remove images during runtime, you can just set the MyImage property to null, or, in the case of a multiple-images (sub)item, use the ArrayList methods, such as Add() and RemoveAt(). Examples:

If you want to remove the second image from an EXMulitpleImagesListViewSubItem (second column) in the third row, you do:

C#
EXMultipleImagesListViewSubItem subitem = 
   lstv.Items[2].SubItems[1] 
   as EXMultipleImagesListViewSubItem;
subitem.MyImages.RemoveAt(1);
lstv.Invalidate(subitem.Bounds);

You must invalidate this rectangle yourself.

Adjusting the heights of rows

Because all the drawing is done in the owner-draw events, the SmallImageList property is only used to show the up and down arrows in the column headers and not to show images in the ListViewItem. To adjust the row height, you assign an ImageList and set the Size to the appropriate size. This is a dirty hack, but the only way I could do it. If you can find another way - please let me know.

Adding controls

To add a control to a subitem, create a EXControlListViewSubItem, then create the control, add the EXControlListViewSubItem to the listviewitem, and at last, add the control to the EXControlListViewSubItem with the EXListView method AddControlToSubitem:

C#
EXListViewItem item = new EXListViewItem("Item 1");
EXControlListViewSubItem cs = new EXControlListViewSubItem();
ProgressBar b = new ProgressBar();
b.Minimum = 0;
b.Maximum = 1000;
b.Step = 1;
item.SubItems.Add(cs);
lstv.AddControlToSubItem(b, cs);

Points of interest

There is, at this point, an irritating bug in the EXListView class: when you move your mouse pointer into the ListView from left to right, the DrawItem event will be fired, but accompanied by the DrawSubItem event. So, the ListViewItem will be repainted, but the subitems will not. If the content of the ListViewItem (represented by the first subitem) is larger than the column, the content falls over the neighboring subitems.

History

  • Created on 9 February 2006.
  • Updated code and article: now you can edit columns with images as well - 15 February 2006.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Netherlands Netherlands
...to be continued.

Comments and Discussions

 
Questionhide column header Pin
artor42213-Mar-18 23:32
artor42213-Mar-18 23:32 
QuestionBug + Solution: Added Controls (via AddControlToSubItem(...)) are painted over the ColumnHeaders (if scrolled) Pin
Member 134478455-Oct-17 23:36
Member 134478455-Oct-17 23:36 
Fix: Added Column Header height Check
Look for comments starting with //TH:

namespace EXControls
{

    public class EXListView : ListView
    {

        private ListViewItem.ListViewSubItem _clickedsubitem; //clicked ListViewSubItem
        private ListViewItem _clickeditem; //clicked ListViewItem
        private int _col; //index of doubleclicked ListViewSubItem
        private TextBox txtbx; //the default edit control
        private int _sortcol; //index of clicked ColumnHeader
        private Brush _sortcolbrush; //color of items in sorted column
        private Brush _highlightbrush; //color of highlighted items
        private int _cpadding; //padding of the embedded controls

        //TH:   Added Column Header Height
        private int _colHeaderHeight;

        private const UInt32 LVM_FIRST = 0x1000;
        private const UInt32 LVM_SCROLL = (LVM_FIRST + 20);

        //TH:   Added for GetWindowRect(...) to check Column Header Height
        private const UInt32 LVM_GETHEADER = (LVM_FIRST + 31);

        private const int WM_HSCROLL = 0x114;
        private const int WM_VSCROLL = 0x115;
        private const int WM_MOUSEWHEEL = 0x020A;
        private const int WM_PAINT = 0x000F;

        private struct EmbeddedControl
        {
            public Control MyControl;
            public EXControlListViewSubItem MySubItem;
        }

        private ArrayList _controls;

        [DllImport("user32.dll")]
        private static extern bool SendMessage(IntPtr hWnd, UInt32 m, int wParam, int lParam);

        //TH:   Added SendMessage2(...) + GetWindowRect(...) to check Column Header Height
        private struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }
        [DllImport("user32.dll", EntryPoint = "SendMessage")]
        private static extern IntPtr SendMessage2(IntPtr hwnd, long wMsg, long wParam, long lParam);

        [DllImport("user32.dll")]
        private static extern bool GetWindowRect(HandleRef hwnd, out RECT lpRect);


        protected override void WndProc(ref Message m)
        {
            if (m.Msg == WM_PAINT)
            {
                foreach (EmbeddedControl c in _controls)
                {
                    Rectangle r = c.MySubItem.Bounds;

                    //TH:   Added Column Header Height offset (_colHeaderHeight).

                    //if (r.Y > 0 && r.Y < this.ClientRectangle.Height)
                    if ((r.Y > (0 + _colHeaderHeight)) && (r.Y < this.ClientRectangle.Height))
                    {
                        c.MyControl.Visible = true;
                        c.MyControl.Bounds = new Rectangle(r.X + _cpadding, r.Y + _cpadding, r.Width - (2 * _cpadding), r.Height - (2 * _cpadding));
                    }
                    else
                    {
                        c.MyControl.Visible = false;
                    }
                }
            }
            switch (m.Msg)
            {
                case WM_HSCROLL:
                case WM_VSCROLL:
                case WM_MOUSEWHEEL:
                    this.Focus();
                    break;
            }
            base.WndProc(ref m);
        }

        //TH:   Added Column Header Height check. Call this after Column Header setup is done.
        public void InitColumnHeaderHeight()
        {
            _colHeaderHeight = 0;
            RECT rc = new RECT();
            IntPtr hwnd = SendMessage2(this.Handle, LVM_GETHEADER, 0, 0);
            if (hwnd != null)
            {
                if (GetWindowRect(new HandleRef(null, hwnd), out rc))
                {
                    _colHeaderHeight = rc.Bottom - rc.Top - 1;  //-1 is neccessary to show Control for Top Item
                }
            }
        }

        private void ScrollMe(int x, int y)
        {
            SendMessage((IntPtr)this.Handle, LVM_SCROLL, x, y);
        }

        public EXListView()
        {
            _cpadding = 4;
            _controls = new ArrayList();
            _sortcol = -1;
            _sortcolbrush = SystemBrushes.ControlLight;
            _highlightbrush = SystemBrushes.Highlight;

            //TH:   Added Column Header Height
            _colHeaderHeight = 0;

            this.OwnerDraw = true;
            this.FullRowSelect = true;
            this.View = View.Details;
            this.MouseDown += new MouseEventHandler(this_MouseDown);
            this.MouseDoubleClick += new MouseEventHandler(this_MouseDoubleClick);
            this.DrawColumnHeader += new DrawListViewColumnHeaderEventHandler(this_DrawColumnHeader);
            this.DrawSubItem += new DrawListViewSubItemEventHandler(this_DrawSubItem);
            this.MouseMove += new MouseEventHandler(this_MouseMove);
            this.ColumnClick += new ColumnClickEventHandler(this_ColumnClick);
            txtbx = new TextBox();
            txtbx.Visible = false;
            this.Controls.Add(txtbx);
            txtbx.Leave += new EventHandler(c_Leave);
            txtbx.KeyPress += new KeyPressEventHandler(txtbx_KeyPress);
        }

        public void AddControlToSubItem(Control control, EXControlListViewSubItem subitem)
        {
            this.Controls.Add(control);
            subitem.MyControl = control;
            EmbeddedControl ec;
            ec.MyControl = control;
            ec.MySubItem = subitem;
            this._controls.Add(ec);
        }

        public void RemoveControlFromSubItem(EXControlListViewSubItem subitem)
        {
            Control c = subitem.MyControl;
            for (int i = 0; i < this._controls.Count; i++)
            {
                if (((EmbeddedControl)this._controls[i]).MySubItem == subitem)
                {
                    this._controls.RemoveAt(i);
                    subitem.MyControl = null;
                    this.Controls.Remove(c);
                    c.Dispose();
                    return;
                }
            }
        }

        public int ControlPadding
        {
            get { return _cpadding; }
            set { _cpadding = value; }
        }

        public Brush MySortBrush
        {
            get { return _sortcolbrush; }
            set { _sortcolbrush = value; }
        }

        public Brush MyHighlightBrush
        {
            get { return _highlightbrush; }
            set { _highlightbrush = value; }
        }

        private void txtbx_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == (char)Keys.Return)
            {
                _clickedsubitem.Text = txtbx.Text;
                txtbx.Visible = false;
                _clickeditem.Tag = null;
            }
        }

        private void c_Leave(object sender, EventArgs e)
        {
            Control c = (Control)sender;
            _clickedsubitem.Text = c.Text;
            c.Visible = false;
            _clickeditem.Tag = null;
        }

        private void this_MouseDown(object sender, MouseEventArgs e)
        {
            ListViewHitTestInfo lstvinfo = this.HitTest(e.X, e.Y);
            ListViewItem.ListViewSubItem subitem = lstvinfo.SubItem;
            if (subitem == null) return;
            int subx = subitem.Bounds.Left;
            if (subx < 0)
            {
                this.ScrollMe(subx, 0);
            }
        }

        private void this_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            EXListViewItem lstvItem = this.GetItemAt(e.X, e.Y) as EXListViewItem;
            if (lstvItem == null) return;
            _clickeditem = lstvItem;
            int x = lstvItem.Bounds.Left;
            int i;
            for (i = 0; i < this.Columns.Count; i++)
            {
                x = x + this.Columns[i].Width;
                if (x > e.X)
                {
                    x = x - this.Columns[i].Width;
                    _clickedsubitem = lstvItem.SubItems[i];
                    _col = i;
                    break;
                }
            }
            if (!(this.Columns[i] is EXColumnHeader)) return;
            EXColumnHeader col = (EXColumnHeader)this.Columns[i];
            if (col.GetType() == typeof(EXEditableColumnHeader))
            {
                EXEditableColumnHeader editcol = (EXEditableColumnHeader)col;
                if (editcol.MyControl != null)
                {
                    Control c = editcol.MyControl;
                    if (c.Tag != null)
                    {
                        this.Controls.Add(c);
                        c.Tag = null;
                        if (c is ComboBox)
                        {
                            ((ComboBox)c).SelectedValueChanged += new EventHandler(cmbx_SelectedValueChanged);
                        }
                        c.Leave += new EventHandler(c_Leave);
                    }
                    c.Location = new Point(x, this.GetItemRect(this.Items.IndexOf(lstvItem)).Y);
                    c.Width = this.Columns[i].Width;
                    if (c.Width > this.Width) c.Width = this.ClientRectangle.Width;
                    c.Text = _clickedsubitem.Text;
                    c.Visible = true;
                    c.BringToFront();
                    c.Focus();
                }
                else
                {
                    txtbx.Location = new Point(x, this.GetItemRect(this.Items.IndexOf(lstvItem)).Y);
                    txtbx.Width = this.Columns[i].Width;
                    if (txtbx.Width > this.Width) txtbx.Width = this.ClientRectangle.Width;
                    txtbx.Text = _clickedsubitem.Text;
                    txtbx.Visible = true;
                    txtbx.BringToFront();
                    txtbx.Focus();
                }
            }
            else if (col.GetType() == typeof(EXBoolColumnHeader))
            {
                EXBoolColumnHeader boolcol = (EXBoolColumnHeader)col;
                if (boolcol.Editable)
                {
                    EXBoolListViewSubItem boolsubitem = (EXBoolListViewSubItem)_clickedsubitem;
                    if (boolsubitem.BoolValue == true)
                    {
                        boolsubitem.BoolValue = false;
                    }
                    else
                    {
                        boolsubitem.BoolValue = true;
                    }
                    this.Invalidate(boolsubitem.Bounds);
                }
            }
        }

        private void cmbx_SelectedValueChanged(object sender, EventArgs e)
        {
            if (((Control)sender).Visible == false || _clickedsubitem == null) return;
            if (sender.GetType() == typeof(EXComboBox))
            {
                EXComboBox excmbx = (EXComboBox)sender;
                object item = excmbx.SelectedItem;
                //Is this an combobox item with one image?
                if (item.GetType() == typeof(EXComboBox.EXImageItem))
                {
                    EXComboBox.EXImageItem imgitem = (EXComboBox.EXImageItem)item;
                    //Is the first column clicked -- in that case it's a ListViewItem
                    if (_col == 0)
                    {
                        if (_clickeditem.GetType() == typeof(EXImageListViewItem))
                        {
                            ((EXImageListViewItem)_clickeditem).MyImage = imgitem.MyImage;
                        }
                        else if (_clickeditem.GetType() == typeof(EXMultipleImagesListViewItem))
                        {
                            EXMultipleImagesListViewItem imglstvitem = (EXMultipleImagesListViewItem)_clickeditem;
                            imglstvitem.MyImages.Clear();
                            imglstvitem.MyImages.AddRange(new object[] { imgitem.MyImage });
                        }
                        //another column than the first one is clicked, so we have a ListViewSubItem
                    }
                    else
                    {
                        if (_clickedsubitem.GetType() == typeof(EXImageListViewSubItem))
                        {
                            EXImageListViewSubItem imgsub = (EXImageListViewSubItem)_clickedsubitem;
                            imgsub.MyImage = imgitem.MyImage;
                        }
                        else if (_clickedsubitem.GetType() == typeof(EXMultipleImagesListViewSubItem))
                        {
                            EXMultipleImagesListViewSubItem imgsub = (EXMultipleImagesListViewSubItem)_clickedsubitem;
                            imgsub.MyImages.Clear();
                            imgsub.MyImages.Add(imgitem.MyImage);
                            imgsub.MyValue = imgitem.MyValue;
                        }
                    }
                    //or is this a combobox item with multiple images?
                }
                else if (item.GetType() == typeof(EXComboBox.EXMultipleImagesItem))
                {
                    EXComboBox.EXMultipleImagesItem imgitem = (EXComboBox.EXMultipleImagesItem)item;
                    if (_col == 0)
                    {
                        if (_clickeditem.GetType() == typeof(EXImageListViewItem))
                        {
                            ((EXImageListViewItem)_clickeditem).MyImage = (Image)imgitem.MyImages[0];
                        }
                        else if (_clickeditem.GetType() == typeof(EXMultipleImagesListViewItem))
                        {
                            EXMultipleImagesListViewItem imglstvitem = (EXMultipleImagesListViewItem)_clickeditem;
                            imglstvitem.MyImages.Clear();
                            imglstvitem.MyImages.AddRange(imgitem.MyImages);
                        }
                    }
                    else
                    {
                        if (_clickedsubitem.GetType() == typeof(EXImageListViewSubItem))
                        {
                            EXImageListViewSubItem imgsub = (EXImageListViewSubItem)_clickedsubitem;
                            if (imgitem.MyImages != null)
                            {
                                imgsub.MyImage = (Image)imgitem.MyImages[0];
                            }
                        }
                        else if (_clickedsubitem.GetType() == typeof(EXMultipleImagesListViewSubItem))
                        {
                            EXMultipleImagesListViewSubItem imgsub = (EXMultipleImagesListViewSubItem)_clickedsubitem;
                            imgsub.MyImages.Clear();
                            imgsub.MyImages.AddRange(imgitem.MyImages);
                            imgsub.MyValue = imgitem.MyValue;
                        }
                    }
                }
            }
            ComboBox c = (ComboBox)sender;
            _clickedsubitem.Text = c.Text;
            c.Visible = false;
            _clickeditem.Tag = null;
        }

        private void this_MouseMove(object sender, MouseEventArgs e)
        {
            ListViewItem item = this.GetItemAt(e.X, e.Y);
            if (item != null && item.Tag == null)
            {
                this.Invalidate(item.Bounds);
                item.Tag = "t";
            }
        }

        private void this_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
        {
            e.DrawDefault = true;
        }

        private void this_DrawSubItem(object sender, DrawListViewSubItemEventArgs e)
        {
            e.DrawBackground();
            if (e.ColumnIndex == _sortcol)
            {
                e.Graphics.FillRectangle(_sortcolbrush, e.Bounds);
            }
            if ((e.ItemState & ListViewItemStates.Selected) != 0)
            {
                e.Graphics.FillRectangle(_highlightbrush, e.Bounds);
            }
            int fonty = e.Bounds.Y + ((int)(e.Bounds.Height / 2)) - ((int)(e.SubItem.Font.Height / 2));
            int x = e.Bounds.X + 2;
            if (e.ColumnIndex == 0)
            {
                EXListViewItem item = (EXListViewItem)e.Item;
                if (item.GetType() == typeof(EXImageListViewItem))
                {
                    EXImageListViewItem imageitem = (EXImageListViewItem)item;
                    if (imageitem.MyImage != null)
                    {
                        Image img = imageitem.MyImage;
                        int imgy = e.Bounds.Y + ((int)(e.Bounds.Height / 2)) - ((int)(img.Height / 2));
                        e.Graphics.DrawImage(img, x, imgy, img.Width, img.Height);
                        x += img.Width + 2;
                    }
                }
                e.Graphics.DrawString(e.SubItem.Text, e.SubItem.Font, new SolidBrush(e.SubItem.ForeColor), x, fonty);
                return;
            }
            EXListViewSubItemAB subitem = e.SubItem as EXListViewSubItemAB;
            if (subitem == null)
            {
                e.DrawDefault = true;
            }
            else
            {
                x = subitem.DoDraw(e, x, this.Columns[e.ColumnIndex] as EXColumnHeader);
                e.Graphics.DrawString(e.SubItem.Text, e.SubItem.Font, new SolidBrush(e.SubItem.ForeColor), x, fonty);
            }
        }

        private void this_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            if (this.Items.Count == 0) return;
            for (int i = 0; i < this.Columns.Count; i++)
            {
                this.Columns[i].ImageKey = null;
            }
            for (int i = 0; i < this.Items.Count; i++)
            {
                this.Items[i].Tag = null;
            }
            if (e.Column != _sortcol)
            {
                _sortcol = e.Column;
                this.Sorting = SortOrder.Ascending;
                this.Columns[e.Column].ImageKey = "up";
            }
            else
            {
                if (this.Sorting == SortOrder.Ascending)
                {
                    this.Sorting = SortOrder.Descending;
                    this.Columns[e.Column].ImageKey = "down";
                }
                else
                {
                    this.Sorting = SortOrder.Ascending;
                    this.Columns[e.Column].ImageKey = "up";
                }
            }
            if (_sortcol == 0)
            {
                //ListViewItem
                if (this.Items[0].GetType() == typeof(EXListViewItem))
                {
                    //sorting on text
                    this.ListViewItemSorter = new ListViewItemComparerText(e.Column, this.Sorting);
                }
                else
                {
                    //sorting on value
                    this.ListViewItemSorter = new ListViewItemComparerValue(e.Column, this.Sorting);
                }
            }
            else
            {
                //ListViewSubItem
                if (this.Items[0].SubItems[_sortcol].GetType() == typeof(EXListViewSubItemAB))
                {
                    //sorting on text
                    this.ListViewItemSorter = new ListViewSubItemComparerText(e.Column, this.Sorting);
                }
                else
                {
                    //sorting on value
                    this.ListViewItemSorter = new ListViewSubItemComparerValue(e.Column, this.Sorting);
                }
            }
        }

        class ListViewSubItemComparerText : System.Collections.IComparer
        {

            private int _col;
            private SortOrder _order;

            public ListViewSubItemComparerText()
            {
                _col = 0;
                _order = SortOrder.Ascending;
            }

            public ListViewSubItemComparerText(int col, SortOrder order)
            {
                _col = col;
                _order = order;
            }

            public int Compare(object x, object y)
            {
                int returnVal = -1;

                string xstr = ((ListViewItem)x).SubItems[_col].Text;
                string ystr = ((ListViewItem)y).SubItems[_col].Text;

                decimal dec_x;
                decimal dec_y;
                DateTime dat_x;
                DateTime dat_y;

                if (Decimal.TryParse(xstr, out dec_x) && Decimal.TryParse(ystr, out dec_y))
                {
                    returnVal = Decimal.Compare(dec_x, dec_y);
                }
                else if (DateTime.TryParse(xstr, out dat_x) && DateTime.TryParse(ystr, out dat_y))
                {
                    returnVal = DateTime.Compare(dat_x, dat_y);
                }
                else
                {
                    returnVal = String.Compare(xstr, ystr);
                }
                if (_order == SortOrder.Descending) returnVal *= -1;
                return returnVal;
            }

        }

        class ListViewSubItemComparerValue : System.Collections.IComparer
        {

            private int _col;
            private SortOrder _order;

            public ListViewSubItemComparerValue()
            {
                _col = 0;
                _order = SortOrder.Ascending;
            }

            public ListViewSubItemComparerValue(int col, SortOrder order)
            {
                _col = col;
                _order = order;
            }

            public int Compare(object x, object y)
            {
                int returnVal = -1;

                string xstr = ((EXListViewSubItemAB)((ListViewItem)x).SubItems[_col]).MyValue;
                string ystr = ((EXListViewSubItemAB)((ListViewItem)y).SubItems[_col]).MyValue;

                decimal dec_x;
                decimal dec_y;
                DateTime dat_x;
                DateTime dat_y;

                if (Decimal.TryParse(xstr, out dec_x) && Decimal.TryParse(ystr, out dec_y))
                {
                    returnVal = Decimal.Compare(dec_x, dec_y);
                }
                else if (DateTime.TryParse(xstr, out dat_x) && DateTime.TryParse(ystr, out dat_y))
                {
                    returnVal = DateTime.Compare(dat_x, dat_y);
                }
                else
                {
                    returnVal = String.Compare(xstr, ystr);
                }
                if (_order == SortOrder.Descending) returnVal *= -1;
                return returnVal;
            }

        }

        class ListViewItemComparerText : System.Collections.IComparer
        {

            private int _col;
            private SortOrder _order;

            public ListViewItemComparerText()
            {
                _col = 0;
                _order = SortOrder.Ascending;
            }

            public ListViewItemComparerText(int col, SortOrder order)
            {
                _col = col;
                _order = order;
            }

            public int Compare(object x, object y)
            {
                int returnVal = -1;

                string xstr = ((ListViewItem)x).Text;
                string ystr = ((ListViewItem)y).Text;

                decimal dec_x;
                decimal dec_y;
                DateTime dat_x;
                DateTime dat_y;

                if (Decimal.TryParse(xstr, out dec_x) && Decimal.TryParse(ystr, out dec_y))
                {
                    returnVal = Decimal.Compare(dec_x, dec_y);
                }
                else if (DateTime.TryParse(xstr, out dat_x) && DateTime.TryParse(ystr, out dat_y))
                {
                    returnVal = DateTime.Compare(dat_x, dat_y);
                }
                else
                {
                    returnVal = String.Compare(xstr, ystr);
                }
                if (_order == SortOrder.Descending) returnVal *= -1;
                return returnVal;
            }

        }

        class ListViewItemComparerValue : System.Collections.IComparer
        {

            private int _col;
            private SortOrder _order;

            public ListViewItemComparerValue()
            {
                _col = 0;
                _order = SortOrder.Ascending;
            }

            public ListViewItemComparerValue(int col, SortOrder order)
            {
                _col = col;
                _order = order;
            }

            public int Compare(object x, object y)
            {
                int returnVal = -1;

                string xstr = ((EXListViewItem)x).MyValue;
                string ystr = ((EXListViewItem)y).MyValue;

                decimal dec_x;
                decimal dec_y;
                DateTime dat_x;
                DateTime dat_y;

                if (Decimal.TryParse(xstr, out dec_x) && Decimal.TryParse(ystr, out dec_y))
                {
                    returnVal = Decimal.Compare(dec_x, dec_y);
                }
                else if (DateTime.TryParse(xstr, out dat_x) && DateTime.TryParse(ystr, out dat_y))
                {
                    returnVal = DateTime.Compare(dat_x, dat_y);
                }
                else
                {
                    returnVal = String.Compare(xstr, ystr);
                }
                if (_order == SortOrder.Descending) returnVal *= -1;
                return returnVal;
            }

        }

    }

    public class EXColumnHeader : ColumnHeader
    {

        public EXColumnHeader()
        {

        }

        public EXColumnHeader(string text)
        {
            this.Text = text;
        }

        public EXColumnHeader(string text, int width)
        {
            this.Text = text;
            this.Width = width;
        }

    }

    public class EXEditableColumnHeader : EXColumnHeader
    {

        private Control _control;

        public EXEditableColumnHeader()
        {

        }

        public EXEditableColumnHeader(string text)
        {
            this.Text = text;
        }

        public EXEditableColumnHeader(string text, int width)
        {
            this.Text = text;
            this.Width = width;
        }

        public EXEditableColumnHeader(string text, Control control)
        {
            this.Text = text;
            this.MyControl = control;
        }

        public EXEditableColumnHeader(string text, Control control, int width)
        {
            this.Text = text;
            this.MyControl = control;
            this.Width = width;
        }

        public Control MyControl
        {
            get { return _control; }
            set
            {
                _control = value;
                _control.Visible = false;
                _control.Tag = "not_init";
            }
        }

    }

    public class EXBoolColumnHeader : EXColumnHeader
    {

        private Image _trueimage;
        private Image _falseimage;
        private bool _editable;

        public EXBoolColumnHeader()
        {
            init();
        }

        public EXBoolColumnHeader(string text)
        {
            init();
            this.Text = text;
        }

        public EXBoolColumnHeader(string text, int width)
        {
            init();
            this.Text = text;
            this.Width = width;
        }

        public EXBoolColumnHeader(string text, Image trueimage, Image falseimage)
        {
            init();
            this.Text = text;
            _trueimage = trueimage;
            _falseimage = falseimage;
        }

        public EXBoolColumnHeader(string text, Image trueimage, Image falseimage, int width)
        {
            init();
            this.Text = text;
            _trueimage = trueimage;
            _falseimage = falseimage;
            this.Width = width;
        }

        private void init()
        {
            _editable = false;
        }

        public Image TrueImage
        {
            get { return _trueimage; }
            set { _trueimage = value; }
        }

        public Image FalseImage
        {
            get { return _falseimage; }
            set { _falseimage = value; }
        }

        public bool Editable
        {
            get { return _editable; }
            set { _editable = value; }
        }

    }

    public abstract class EXListViewSubItemAB : ListViewItem.ListViewSubItem
    {

        private string _value = "";

        public EXListViewSubItemAB()
        {

        }

        public EXListViewSubItemAB(string text)
        {
            this.Text = text;
        }

        public string MyValue
        {
            get { return _value; }
            set { _value = value; }
        }

        //return the new x coordinate
        public abstract int DoDraw(DrawListViewSubItemEventArgs e, int x, EXControls.EXColumnHeader ch);

    }

    public class EXListViewSubItem : EXListViewSubItemAB
    {

        public EXListViewSubItem()
        {

        }

        public EXListViewSubItem(string text)
        {
            this.Text = text;
        }

        public override int DoDraw(DrawListViewSubItemEventArgs e, int x, EXControls.EXColumnHeader ch)
        {
            return x;
        }

    }

    public class EXControlListViewSubItem : EXListViewSubItemAB
    {

        private Control _control;

        public EXControlListViewSubItem()
        {

        }

        public Control MyControl
        {
            get { return _control; }
            set { _control = value; }
        }

        public override int DoDraw(DrawListViewSubItemEventArgs e, int x, EXColumnHeader ch)
        {
            return x;
        }

    }

    public class EXImageListViewSubItem : EXListViewSubItemAB
    {

        private Image _image;

        public EXImageListViewSubItem()
        {

        }

        public EXImageListViewSubItem(string text)
        {
            this.Text = text;
        }

        public EXImageListViewSubItem(Image image)
        {
            _image = image;
        }

        public EXImageListViewSubItem(Image image, string value)
        {
            _image = image;
            this.MyValue = value;
        }

        public EXImageListViewSubItem(string text, Image image, string value)
        {
            this.Text = text;
            _image = image;
            this.MyValue = value;
        }

        public Image MyImage
        {
            get { return _image; }
            set { _image = value; }
        }

        public override int DoDraw(DrawListViewSubItemEventArgs e, int x, EXControls.EXColumnHeader ch)
        {
            if (this.MyImage != null)
            {
                Image img = this.MyImage;
                int imgy = e.Bounds.Y + ((int)(e.Bounds.Height / 2)) - ((int)(img.Height / 2));
                e.Graphics.DrawImage(img, x, imgy, img.Width, img.Height);
                x += img.Width + 2;
            }
            return x;
        }

    }

    public class EXMultipleImagesListViewSubItem : EXListViewSubItemAB
    {

        private ArrayList _images;

        public EXMultipleImagesListViewSubItem()
        {

        }

        public EXMultipleImagesListViewSubItem(string text)
        {
            this.Text = text;
        }

        public EXMultipleImagesListViewSubItem(ArrayList images)
        {
            _images = images;
        }

        public EXMultipleImagesListViewSubItem(ArrayList images, string value)
        {
            _images = images;
            this.MyValue = value;
        }

        public EXMultipleImagesListViewSubItem(string text, ArrayList images, string value)
        {
            this.Text = text;
            _images = images;
            this.MyValue = value;
        }

        public ArrayList MyImages
        {
            get { return _images; }
            set { _images = value; }
        }

        public override int DoDraw(DrawListViewSubItemEventArgs e, int x, EXColumnHeader ch)
        {
            if (this.MyImages != null && this.MyImages.Count > 0)
            {
                for (int i = 0; i < this.MyImages.Count; i++)
                {
                    Image img = (Image)this.MyImages[i];
                    int imgy = e.Bounds.Y + ((int)(e.Bounds.Height / 2)) - ((int)(img.Height / 2));
                    e.Graphics.DrawImage(img, x, imgy, img.Width, img.Height);
                    x += img.Width + 2;
                }
            }
            return x;
        }

    }

    public class EXBoolListViewSubItem : EXListViewSubItemAB
    {

        private bool _value;

        public EXBoolListViewSubItem()
        {

        }

        public EXBoolListViewSubItem(bool val)
        {
            _value = val;
            this.MyValue = val.ToString();
        }

        public bool BoolValue
        {
            get { return _value; }
            set
            {
                _value = value;
                this.MyValue = value.ToString();
            }
        }

        public override int DoDraw(DrawListViewSubItemEventArgs e, int x, EXColumnHeader ch)
        {
            EXBoolColumnHeader boolcol = (EXBoolColumnHeader)ch;
            Image boolimg;
            if (this.BoolValue == true)
            {
                boolimg = boolcol.TrueImage;
            }
            else
            {
                boolimg = boolcol.FalseImage;
            }
            int imgy = e.Bounds.Y + ((int)(e.Bounds.Height / 2)) - ((int)(boolimg.Height / 2));
            e.Graphics.DrawImage(boolimg, x, imgy, boolimg.Width, boolimg.Height);
            x += boolimg.Width + 2;
            return x;
        }

    }

    public class EXListViewItem : ListViewItem
    {

        private string _value;

        public EXListViewItem()
        {

        }

        public EXListViewItem(string text)
        {
            this.Text = text;
        }

        public string MyValue
        {
            get { return _value; }
            set { _value = value; }
        }

    }

    public class EXImageListViewItem : EXListViewItem
    {

        private Image _image;

        public EXImageListViewItem()
        {

        }

        public EXImageListViewItem(string text)
        {
            this.Text = text;
        }

        public EXImageListViewItem(Image image)
        {
            _image = image;
        }

        public EXImageListViewItem(string text, Image image)
        {
            _image = image;
            this.Text = text;
        }

        public EXImageListViewItem(string text, Image image, string value)
        {
            this.Text = text;
            _image = image;
            this.MyValue = value;
        }

        public Image MyImage
        {
            get { return _image; }
            set { _image = value; }
        }

    }

    public class EXMultipleImagesListViewItem : EXListViewItem
    {

        private ArrayList _images;

        public EXMultipleImagesListViewItem()
        {

        }

        public EXMultipleImagesListViewItem(string text)
        {
            this.Text = text;
        }

        public EXMultipleImagesListViewItem(ArrayList images)
        {
            _images = images;
        }

        public EXMultipleImagesListViewItem(string text, ArrayList images)
        {
            this.Text = text;
            _images = images;
        }

        public EXMultipleImagesListViewItem(string text, ArrayList images, string value)
        {
            this.Text = text;
            _images = images;
            this.MyValue = value;
        }

        public ArrayList MyImages
        {
            get { return _images; }
            set { _images = value; }
        }

    }

}

QuestionA little bug! Pin
umar.techBOY13-Jun-16 0:57
umar.techBOY13-Jun-16 0:57 
AnswerRe: A little bug! Pin
umar.techBOY13-Jun-16 1:10
umar.techBOY13-Jun-16 1:10 
QuestionVariable Row Hieght for each row Pin
Shomy18-Feb-16 11:45
Shomy18-Feb-16 11:45 
GeneralMy vote of 5 Pin
Riktek3-Jan-14 1:19
Riktek3-Jan-14 1:19 
QuestionEvent KeyDown? Pin
KishanAhir28-Dec-13 10:29
KishanAhir28-Dec-13 10:29 
Questionhow to add multiple controls in subitem Pin
RAshmiBhimani10-Oct-13 0:45
RAshmiBhimani10-Oct-13 0:45 
GeneralMy vote of 5 Pin
m.qayyum9-Sep-13 11:25
m.qayyum9-Sep-13 11:25 
GeneralMy vote of 5 Pin
Shahan Ayyub26-Mar-13 7:46
Shahan Ayyub26-Mar-13 7:46 
QuestionUrgent help: How to stop user from editing? Pin
shyambs8513-Mar-13 5:00
shyambs8513-Mar-13 5:00 
QuestionCan i free use the source code in a commercial software? Pin
liusfile20-Feb-13 21:10
liusfile20-Feb-13 21:10 
GeneralVery good article. Pin
hkn050930-Jan-13 6:22
hkn050930-Jan-13 6:22 
Question.dll Pin
hujiko98731-Oct-12 18:58
hujiko98731-Oct-12 18:58 
AnswerRe: .dll Pin
hujiko98731-Oct-12 20:50
hujiko98731-Oct-12 20:50 
BugMay be some bugs Pin
fanherong18-Jun-12 21:15
fanherong18-Jun-12 21:15 
GeneralMy vote of 5 Pin
Mr. Ean Soknet27-May-12 17:59
Mr. Ean Soknet27-May-12 17:59 
QuestionGreat Article! Pin
Daniel Liedke4-Apr-12 3:49
professionalDaniel Liedke4-Apr-12 3:49 
QuestionHow to add Group in this listview Pin
JacksonChian1855-Jan-12 18:50
JacksonChian1855-Jan-12 18:50 
QuestionAmazing; just one thing... Pin
PlagueEditor29-Jun-11 16:04
PlagueEditor29-Jun-11 16:04 
GeneralAnimated Image Pin
Sunasara Imdadhusen15-Apr-11 1:56
professionalSunasara Imdadhusen15-Apr-11 1:56 
GeneralSame bug you described still persists.. Pin
divStar7-Nov-10 2:25
divStar7-Nov-10 2:25 
GeneralVB Version please Pin
SiloSino16-Aug-10 8:28
SiloSino16-Aug-10 8:28 
QuestionVB or C# Version ? Pin
realyeti31-Jan-10 1:46
realyeti31-Jan-10 1:46 
Generalright to left Pin
mehrzad200230-Jan-10 23:17
mehrzad200230-Jan-10 23:17 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.