This question has already been solved
You
Since listview control in .net framework 2.0 does not have a datasource property, it is not bindable to neither datatable nor generic lists. i created a derived custom listview that is bindable to lists of any type. i attach the .zip to this thread.
I dedicate this custom windows control to Julienne Walker.
SmartListView.cs :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Reflection;
namespace SmartListView
{
public partial class SmartListView : ListView
{
public SmartListView()
{
InitializeComponent();
}
private IList dataSource = null;
public IList DataSource
{
get
{
return dataSource;
}
set
{
dataSource = value;
if(dataSource != null)
CreateItems();
}
}
private string[] columnHeaders = null;
public string[] ColumnHeaders
{
set
{
columnHeaders = value;
}
}
private void CreateItems()
{
if (dataSource.Count > 0)
{
PropertyInfo[] properties = dataSource[0].GetType().GetProperties();
if(properties.Length > 0)
{
if (columnHeaders != null)
{
foreach (string columnName in columnHeaders)
{
Columns.Add(columnName);
}
}
else
{
foreach (PropertyInfo pInfo in properties)
{
Columns.Add(pInfo.Name);
}
}
for (int i = 0; i < dataSource.Count; i++)
{
ListViewItem lvi = new ListViewItem();
lvi.Text = properties[0].GetValue(dataSource[i],null).ToString();
for (int propIndex = 1; propIndex < properties.Length;propIndex++)
{
lvi.SubItems.Add(properties[propIndex].GetValue(dataSource[i], null).ToString());
}
Items.Add(lvi);
}
}
}
}
}
}
SmartListView.Designer.cs :
namespace SmartListView
{
partial class SmartListView
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.View = System.Windows.Forms.View.Details;
}
#endregion
}
}i combined the code to make it sortable from microsoft :
http://support.microsoft.com/kb/319401
now it became more smarter and is sortable. i again attach the solution. And again dedicate this post to Julienne Walker.
SmartListView.cs :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Reflection;
namespace SmartListView
{
public partial class SmartListView : ListView
{
public SmartListView()
{
InitializeComponent();
}
private IList dataSource = null;
public IList DataSource
{
get
{
return dataSource;
}
set
{
dataSource = value;
if (dataSource != null)
{
try
{
CreateItems();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
private string[] columnHeaders = null;
public string[] ColumnHeaders
{
set
{
columnHeaders = value;
}
}
private void CreateItems()
{
if (dataSource.Count > 0)
{
PropertyInfo[] properties = dataSource[0].GetType().GetProperties();
if(properties.Length > 0)
{
if (columnHeaders != null)
{
if (columnHeaders.Length == properties.Length)
{
foreach (string columnName in columnHeaders)
{
Columns.Add(columnName);
}
}
else
{
throw new ApplicationException("Column header collection does not match object properties");
}
}
else
{
foreach (PropertyInfo pInfo in properties)
{
Columns.Add(pInfo.Name);
}
}
for (int i = 0; i < dataSource.Count; i++)
{
ListViewItem lvi = new ListViewItem();
lvi.Text = properties[0].GetValue(dataSource[i],null).ToString();
for (int propIndex = 1; propIndex < properties.Length;propIndex++)
{
lvi.SubItems.Add(properties[propIndex].GetValue(dataSource[i], null).ToString());
}
Items.Add(lvi);
}
}
}
}
#region Sorting Functionality
private ListViewColumnSorter lvwColumnSorter;
/// <summary>
/// This class is an implementation of the 'IComparer' interface.
/// </summary>
public class ListViewColumnSorter : IComparer
{
/// <summary>
/// Specifies the column to be sorted
/// </summary>
private int ColumnToSort;
/// <summary>
/// Specifies the order in which to sort (i.e. 'Ascending').
/// </summary>
private SortOrder OrderOfSort;
/// <summary>
/// Case insensitive comparer object
/// </summary>
private CaseInsensitiveComparer ObjectCompare;
/// <summary>
/// Class constructor. Initializes various elements
/// </summary>
public ListViewColumnSorter()
{
// Initialize the column to '0'
ColumnToSort = 0;
// Initialize the sort order to 'none'
OrderOfSort = SortOrder.None;
// Initialize the CaseInsensitiveComparer object
ObjectCompare = new CaseInsensitiveComparer();
}
/// <summary>
/// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison.
/// </summary>
/// <param name="x">First object to be compared</param>
/// <param name="y">Second object to be compared</param>
/// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
public int Compare(object x, object y)
{
int compareResult;
ListViewItem listviewX, listviewY;
// Cast the objects to be compared to ListViewItem objects
listviewX = (ListViewItem)x;
listviewY = (ListViewItem)y;
// Compare the two items
compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text);
// Calculate correct return value based on object comparison
if (OrderOfSort == SortOrder.Ascending)
{
// Ascending sort is selected, return normal result of compare operation
return compareResult;
}
else if (OrderOfSort == SortOrder.Descending)
{
// Descending sort is selected, return negative result of compare operation
return (-compareResult);
}
else
{
// Return '0' to indicate they are equal
return 0;
}
}
/// <summary>
/// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
/// </summary>
public int SortColumn
{
set
{
ColumnToSort = value;
}
get
{
return ColumnToSort;
}
}
/// <summary>
/// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
/// </summary>
public SortOrder Order
{
set
{
OrderOfSort = value;
}
get
{
return OrderOfSort;
}
}
}
private void SmartListView_ColumnClick(object sender, System.Windows.Forms.ColumnClickEventArgs e)
{
// Determine if clicked column is already the column that is being sorted.
if (e.Column == lvwColumnSorter.SortColumn)
{
// Reverse the current sort direction for this column.
if (lvwColumnSorter.Order == SortOrder.Ascending)
{
lvwColumnSorter.Order = SortOrder.Descending;
}
else
{
lvwColumnSorter.Order = SortOrder.Ascending;
}
}
else
{
// Set the column number that is to be sorted; default to ascending.
lvwColumnSorter.SortColumn = e.Column;
lvwColumnSorter.Order = SortOrder.Ascending;
}
// Perform the sort with these new sort options.
this.Sort();
}
#endregion
}
}
SmartListView.Designer.cs :
namespace SmartListView
{
partial class SmartListView
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.View = System.Windows.Forms.View.Details;
this.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(SmartListView_ColumnClick);
// Create an instance of a ListView column sorter and assign it
// to the ListView control.
lvwColumnSorter = new ListViewColumnSorter();
this.ListViewItemSorter = lvwColumnSorter;
}
#endregion
}
}it now has one more public property to display or hide item number column.
SmartListView.cs :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Reflection;
namespace SmartListView
{
public partial class SmartListView : ListView
{
#region Constructor
public SmartListView()
{
InitializeComponent();
}
#endregion
#region Properties
private IList dataSource = null;
public IList DataSource
{
get
{
return dataSource;
}
set
{
dataSource = value;
if (dataSource != null)
{
try
{
CreateItems();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
private string[] columnHeaders = null;
public string[] ColumnHeaders
{
set
{
columnHeaders = value;
}
}
private bool showNumberColumn = true;
public bool ShowNumberColumn
{
get { return showNumberColumn; }
set { showNumberColumn = value; }
}
#endregion
#region Helper Methods
private void CreateItems()
{
Items.Clear();
Columns.Clear();
if (dataSource.Count > 0)
{
PropertyInfo[] properties = dataSource[0].GetType().GetProperties();
if(properties.Length > 0)
{
if (columnHeaders != null)
{
if (columnHeaders.Length == properties.Length)
{
foreach (string columnName in columnHeaders)
{
Columns.Add(columnName);
}
}
else
{
throw new ApplicationException("Column header collection does not match object properties");
}
}
else
{
foreach (PropertyInfo pInfo in properties)
{
Columns.Add(pInfo.Name);
}
}
if (showNumberColumn)
{
ColumnHeader ch = new ColumnHeader();
ch.Width = -2;
ch.Text = "#";
Columns.Insert(0,ch);
for (int i = 0; i < dataSource.Count; i++)
{
ListViewItem lvi = new ListViewItem();
lvi.Text = (i + 1).ToString();
for (int propIndex=0; propIndex < properties.Length; propIndex++)
{
lvi.SubItems.Add(properties[propIndex].GetValue(dataSource[i], null).ToString());
}
Items.Add(lvi);
}
}
else
{
for (int i = 0; i < dataSource.Count; i++)
{
ListViewItem lvi = new ListViewItem();
lvi.Text = properties[0].GetValue(dataSource[i], null).ToString();
for (int propIndex = 1; propIndex < properties.Length; propIndex++)
{
lvi.SubItems.Add(properties[propIndex].GetValue(dataSource[i], null).ToString());
}
Items.Add(lvi);
}
}
}
}
}
#endregion
#region Sorting Functionality
private ListViewColumnSorter lvwColumnSorter;
/// <summary>
/// This class is an implementation of the 'IComparer' interface.
/// </summary>
public class ListViewColumnSorter : IComparer
{
/// <summary>
/// Specifies the column to be sorted
/// </summary>
private int ColumnToSort;
/// <summary>
/// Specifies the order in which to sort (i.e. 'Ascending').
/// </summary>
private SortOrder OrderOfSort;
/// <summary>
/// Case insensitive comparer object
/// </summary>
private CaseInsensitiveComparer ObjectCompare;
/// <summary>
/// Class constructor. Initializes various elements
/// </summary>
public ListViewColumnSorter()
{
// Initialize the column to '0'
ColumnToSort = 0;
// Initialize the sort order to 'none'
OrderOfSort = SortOrder.None;
// Initialize the CaseInsensitiveComparer object
ObjectCompare = new CaseInsensitiveComparer();
}
/// <summary>
/// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison.
/// </summary>
/// <param name="x">First object to be compared</param>
/// <param name="y">Second object to be compared</param>
/// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
public int Compare(object x, object y)
{
int compareResult;
ListViewItem listviewX, listviewY;
// Cast the objects to be compared to ListViewItem objects
listviewX = (ListViewItem)x;
listviewY = (ListViewItem)y;
// Compare the two items
compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text);
// Calculate correct return value based on object comparison
if (OrderOfSort == SortOrder.Ascending)
{
// Ascending sort is selected, return normal result of compare operation
return compareResult;
}
else if (OrderOfSort == SortOrder.Descending)
{
// Descending sort is selected, return negative result of compare operation
return (-compareResult);
}
else
{
// Return '0' to indicate they are equal
return 0;
}
}
/// <summary>
/// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
/// </summary>
public int SortColumn
{
set
{
ColumnToSort = value;
}
get
{
return ColumnToSort;
}
}
/// <summary>
/// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
/// </summary>
public SortOrder Order
{
set
{
OrderOfSort = value;
}
get
{
return OrderOfSort;
}
}
}
private void SmartListView_ColumnClick(object sender, System.Windows.Forms.ColumnClickEventArgs e)
{
// Determine if clicked column is already the column that is being sorted.
if (e.Column == lvwColumnSorter.SortColumn)
{
// Reverse the current sort direction for this column.
if (lvwColumnSorter.Order == SortOrder.Ascending)
{
lvwColumnSorter.Order = SortOrder.Descending;
}
else
{
lvwColumnSorter.Order = SortOrder.Ascending;
}
}
else
{
// Set the column number that is to be sorted; default to ascending.
lvwColumnSorter.SortColumn = e.Column;
lvwColumnSorter.Order = SortOrder.Ascending;
}
// Perform the sort with these new sort options.
this.Sort();
}
#endregion
}
}
SmartListView.Designer.cs :
namespace SmartListView
{
partial class SmartListView
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
this.View = System.Windows.Forms.View.Details;
this.ColumnClick += new System.Windows.Forms.ColumnClickEventHandler(SmartListView_ColumnClick);
// Create an instance of a ListView column sorter and assign it
// to the ListView control.
lvwColumnSorter = new ListViewColumnSorter();
this.ListViewItemSorter = lvwColumnSorter;
}
#endregion
}
}this is the tester form to use that SmartListView :
Form1.cs :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace Tester
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public class Programmer
{
string name = string.Empty;
public string Name
{
get { return name; }
set { name = value; }
}
string lastName = string.Empty;
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
}
List<Programmer> mylist = new List<Programmer>();
private void button1_Click(object sender, EventArgs e)
{
Programmer p1 = new Programmer();
p1.Name = "Julienne";
p1.LastName = "Walker";
Programmer p2 = new Programmer();
p2.Name = "Serkan";
p2.LastName = "Sendur";
Programmer p3 = new Programmer();
p3.Name = "Adatapost";
p3.LastName = "Adatapost";
Programmer p4 = new Programmer();
p4.Name = "Scott";
p4.LastName = "sknake";
Programmer p5 = new Programmer();
p5.Name = "Ramy";
p5.LastName = "Rahmous";
mylist.Add(p1);
mylist.Add(p2);
mylist.Add(p3);
mylist.Add(p4);
mylist.Add(p5);
smartListView1.ColumnHeaders = new string[] {"Name","Last Name"};
smartListView1.DataSource = mylist;
}
private void button2_Click(object sender, EventArgs e)
{
if (smartListView1.ShowNumberColumn == true)
smartListView1.ShowNumberColumn = false;
else
smartListView1.ShowNumberColumn = true;
smartListView1.DataSource = mylist;
}
}
}
Form1.Designer.cs :
namespace Tester
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.smartListView1 = new SmartListView.SmartListView();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(22, 149);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(90, 23);
this.button1.TabIndex = 1;
this.button1.Text = "Populate";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// smartListView1
//
this.smartListView1.DataSource = null;
this.smartListView1.Location = new System.Drawing.Point(22, 26);
this.smartListView1.Name = "smartListView1";
this.smartListView1.ShowNumberColumn = true;
this.smartListView1.Size = new System.Drawing.Size(245, 109);
this.smartListView1.TabIndex = 2;
this.smartListView1.UseCompatibleStateImageBehavior = false;
this.smartListView1.View = System.Windows.Forms.View.Details;
//
// button2
//
this.button2.Location = new System.Drawing.Point(129, 149);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(138, 23);
this.button2.TabIndex = 3;
this.button2.Text = "Toggle Number Column";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.button2);
this.Controls.Add(this.smartListView1);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button button1;
private SmartListView.SmartListView smartListView1;
private System.Windows.Forms.Button button2;
}
}i noticed that the sorting treats every item as string. so when you try to sort the number column it puts 10 right after 1 thinking that it is a string. so i added an AllNumeric method to see if everything is a number then treat them as integer. I attach the latest version.
SmartListView.cs :
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Reflection;
using System.Text.RegularExpressions;
namespace SmartListView
{
public partial class SmartListView : ListView
{
#region Constructor
public SmartListView()
{
InitializeComponent();
}
#endregion
#region Properties
private IList dataSource = null;
public IList DataSource
{
get
{
return dataSource;
}
set
{
dataSource = value;
if (dataSource != null)
{
try
{
CreateItems();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
private string[] columnHeaders = null;
public string[] ColumnHeaders
{
set
{
columnHeaders = value;
}
}
private bool showNumberColumn = true;
public bool ShowNumberColumn
{
get { return showNumberColumn; }
set { showNumberColumn = value; }
}
#endregion
#region Helper Methods
private void CreateItems()
{
Items.Clear();
Columns.Clear();
if (dataSource.Count > 0)
{
PropertyInfo[] properties = dataSource[0].GetType().GetProperties();
if(properties.Length > 0)
{
if (columnHeaders != null)
{
if (columnHeaders.Length == properties.Length)
{
foreach (string columnName in columnHeaders)
{
Columns.Add(columnName);
}
}
else
{
throw new ApplicationException("Column header collection does not match object properties");
}
}
else
{
foreach (PropertyInfo pInfo in properties)
{
Columns.Add(pInfo.Name);
}
}
if (showNumberColumn)
{
ColumnHeader ch = new ColumnHeader();
ch.Width = -2;
ch.Text = "#";
Columns.Insert(0,ch);
for (int i = 0; i < dataSource.Count; i++)
{
ListViewItem lvi = new ListViewItem();
lvi.Text = (i + 1).ToString();
for (int propIndex=0; propIndex < properties.Length; propIndex++)
{
lvi.SubItems.Add(properties[propIndex].GetValue(dataSource[i], null).ToString());
}
Items.Add(lvi);
}
}
else
{
for (int i = 0; i < dataSource.Count; i++)
{
ListViewItem lvi = new ListViewItem();
lvi.Text = properties[0].GetValue(dataSource[i], null).ToString();
for (int propIndex = 1; propIndex < properties.Length; propIndex++)
{
lvi.SubItems.Add(properties[propIndex].GetValue(dataSource[i], null).ToString());
}
Items.Add(lvi);
}
}
}
}
}
#region IsNumeric
const string ALL_NUMERIC_PATTERN = "[a-z|A-Z]";
static readonly Regex All_Numeric_Regex =
new Regex(ALL_NUMERIC_PATTERN);
static bool AllNumeric(string inputString)
{
if (All_Numeric_Regex.IsMatch(inputString))
{
return false;
}
return true;
}
#endregion
#endregion
#region Sorting Functionality
private ListViewColumnSorter lvwColumnSorter;
/// <summary>
/// This class is an implementation of the 'IComparer' interface.
/// </summary>
public class ListViewColumnSorter : IComparer
{
/// <summary>
/// Specifies the column to be sorted
/// </summary>
private int ColumnToSort;
/// <summary>
/// Specifies the order in which to sort (i.e. 'Ascending').
/// </summary>
private SortOrder OrderOfSort;
/// <summary>
/// Case insensitive comparer object
/// </summary>
private CaseInsensitiveComparer ObjectCompare;
/// <summary>
/// Class constructor. Initializes various elements
/// </summary>
public ListViewColumnSorter()
{
// Initialize the column to '0'
ColumnToSort = 0;
// Initialize the sort order to 'none'
OrderOfSort = SortOrder.None;
// Initialize the CaseInsensitiveComparer object
ObjectCompare = new CaseInsensitiveComparer();
}
/// <summary>
/// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison.
/// </summary>
/// <param name="x">First object to be compared</param>
/// <param name="y">Second object to be compared</param>
/// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
public int Compare(object x, object y)
{
int compareResult;
ListViewItem listviewX, listviewY;
// Cast the objects to be compared to ListViewItem objects
listviewX = (ListViewItem)x;
listviewY = (ListViewItem)y;
// Compare the two items
if (AllNumeric(listviewX.SubItems[ColumnToSort].Text) && AllNumeric(listviewY.SubItems[ColumnToSort].Text))
{
compareResult = ObjectCompare.Compare(Convert.ToInt32(listviewX.SubItems[ColumnToSort].Text),Convert.ToInt32(listviewY.SubItems[ColumnToSort].Text));
}
else
{
compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text);
}
// Calculate correct return value based on object comparison
if (OrderOfSort == SortOrder.Ascending)
{
// Ascending sort is selected, return normal result of compare operation
return compareResult;
}
else if (OrderOfSort == SortOrder.Descending)
{
// Descending sort is selected, return negative result of compare operation
return (-compareResult);
}
else
{
// Return '0' to indicate they are equal
return 0;
}
}
/// <summary>
/// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
/// </summary>
public int SortColumn
{
set
{
ColumnToSort = value;
}
get
{
return ColumnToSort;
}
}
/// <summary>
/// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
/// </summary>
public SortOrder Order
{
set
{
OrderOfSort = value;
}
get
{
return OrderOfSort;
}
}
}
private void SmartListView_ColumnClick(object sender, System.Windows.Forms.ColumnClickEventArgs e)
{
// Determine if clicked column is already the column that is being sorted.
if (e.Column == lvwColumnSorter.SortColumn)
{
// Reverse the current sort direction for this column.
if (lvwColumnSorter.Order == SortOrder.Ascending)
{
lvwColumnSorter.Order = SortOrder.Descending;
}
else
{
lvwColumnSorter.Order = SortOrder.Ascending;
}
}
else
{
// Set the column number that is to be sorted; default to ascending.
lvwColumnSorter.SortColumn = e.Column;
lvwColumnSorter.Order = SortOrder.Ascending;
}
// Perform the sort with these new sort options.
this.Sort();
}
#endregion
}
}i found a bug and modified the code, the final version of the project is attached.
SmartListView.cs :
#region Name Spaces
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Reflection;
using System.Text.RegularExpressions;
#endregion
namespace SmartListView
{
public partial class SmartListView : ListView
{
#region Constructor
public SmartListView()
{
InitializeComponent();
}
#endregion
#region Properties
private IList dataSource = null;
public IList DataSource
{
get
{
return dataSource;
}
set
{
dataSource = value;
if (dataSource != null)
{
try
{
CreateItems();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
private string[] columnHeaders = null;
public string[] ColumnHeaders
{
set
{
columnHeaders = value;
}
}
#endregion
#region Helper Methods
private void CreateItems()
{
Items.Clear();
Columns.Clear();
if (dataSource.Count > 0)
{
PropertyInfo[] properties = dataSource[0].GetType().GetProperties();
if(properties.Length > 0)
{
if (columnHeaders != null)
{
if (columnHeaders.Length == properties.Length)
{
foreach (string columnName in columnHeaders)
{
Columns.Add(columnName);
}
}
else
{
throw new ApplicationException("Column header collection does not match object properties");
}
}
else
{
foreach (PropertyInfo pInfo in properties)
{
Columns.Add(pInfo.Name);
}
}
ColumnHeader ch = new ColumnHeader();
ch.Width = -2;
ch.Text = "#";
Columns.Insert(0,ch);
for (int i = 0; i < dataSource.Count; i++)
{
ListViewItem lvi = new ListViewItem();
lvi.Text = (i + 1).ToString();
for (int propIndex=0; propIndex < properties.Length; propIndex++)
{
lvi.SubItems.Add(properties[propIndex].GetValue(dataSource[i], null).ToString());
}
Items.Add(lvi);
}
}
}
}
#region IsNumeric
const string ALL_NUMERIC_PATTERN = "[a-z|A-Z]";
static readonly Regex All_Numeric_Regex =
new Regex(ALL_NUMERIC_PATTERN);
static bool AllNumeric(string inputString)
{
if (All_Numeric_Regex.IsMatch(inputString))
{
return false;
}
return true;
}
#endregion
#endregion
#region Sorting Functionality
private ListViewColumnSorter lvwColumnSorter;
/// <summary>
/// This class is an implementation of the 'IComparer' interface.
/// </summary>
public class ListViewColumnSorter : IComparer
{
/// <summary>
/// Specifies the column to be sorted
/// </summary>
private int ColumnToSort;
/// <summary>
/// Specifies the order in which to sort (i.e. 'Ascending').
/// </summary>
private SortOrder OrderOfSort;
/// <summary>
/// Case insensitive comparer object
/// </summary>
private CaseInsensitiveComparer ObjectCompare;
/// <summary>
/// Class constructor. Initializes various elements
/// </summary>
public ListViewColumnSorter()
{
// Initialize the column to '0'
ColumnToSort = 0;
// Initialize the sort order to 'none'
OrderOfSort = SortOrder.None;
// Initialize the CaseInsensitiveComparer object
ObjectCompare = new CaseInsensitiveComparer();
}
/// <summary>
/// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison.
/// </summary>
/// <param name="x">First object to be compared</param>
/// <param name="y">Second object to be compared</param>
/// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
public int Compare(object x, object y)
{
int compareResult;
ListViewItem listviewX, listviewY;
// Cast the objects to be compared to ListViewItem objects
listviewX = (ListViewItem)x;
listviewY = (ListViewItem)y;
// Compare the two items
if (AllNumeric(listviewX.SubItems[ColumnToSort].Text) && AllNumeric(listviewY.SubItems[ColumnToSort].Text))
{
compareResult = ObjectCompare.Compare(Convert.ToInt32(listviewX.SubItems[ColumnToSort].Text),Convert.ToInt32(listviewY.SubItems[ColumnToSort].Text));
}
else
{
compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text);
}
// Calculate correct return value based on object comparison
if (OrderOfSort == SortOrder.Ascending)
{
// Ascending sort is selected, return normal result of compare operation
return compareResult;
}
else if (OrderOfSort == SortOrder.Descending)
{
// Descending sort is selected, return negative result of compare operation
return (-compareResult);
}
else
{
// Return '0' to indicate they are equal
return 0;
}
}
/// <summary>
/// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
/// </summary>
public int SortColumn
{
set
{
ColumnToSort = value;
}
get
{
return ColumnToSort;
}
}
/// <summary>
/// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
/// </summary>
public SortOrder Order
{
set
{
OrderOfSort = value;
}
get
{
return OrderOfSort;
}
}
}
private void SmartListView_ColumnClick(object sender, System.Windows.Forms.ColumnClickEventArgs e)
{
// Determine if clicked column is already the column that is being sorted.
if (e.Column == lvwColumnSorter.SortColumn)
{
// Reverse the current sort direction for this column.
if (lvwColumnSorter.Order == SortOrder.Ascending)
{
lvwColumnSorter.Order = SortOrder.Descending;
}
else
{
lvwColumnSorter.Order = SortOrder.Ascending;
}
}
else
{
// Set the column number that is to be sorted; default to ascending.
lvwColumnSorter.SortColumn = e.Column;
lvwColumnSorter.Order = SortOrder.Ascending;
}
// Perform the sort with these new sort options.
this.Sort();
}
#endregion
}
}this is a smart windows form to display lists. it uses the SmartListView that i created. By using this form, you can display any
list of objects and grab the selected ones from it.
SmartListForm.cs :
#region Name Spaces
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;
#endregion
namespace SmartControls
{
public partial class SmartListForm : Form
{
#region Properties
public IList DataSource
{
get
{
return smartListView1.DataSource;
}
set
{
if (value != null)
smartListView1.DataSource = value;
else
throw new ApplicationException("DataSource can not be null");
}
}
public string[] ColumnHeaders
{
set
{
smartListView1.ColumnHeaders = value;
}
}
private IList selectedItems= null;
public IList SelectedItems
{
get
{
return selectedItems;
}
set
{
selectedItems = value;
}
}
#endregion
#region Constructor
public SmartListForm()
{
InitializeComponent();
}
public SmartListForm(IList _selectedItems)
{
SelectedItems = _selectedItems;
InitializeComponent();
}
#endregion
#region Event Handlers
private void SmartListForm_Load(object sender, EventArgs e)
{
smartListView1.Items[0].Selected = true;
}
private void btnOK_Click(object sender, EventArgs e)
{
if (SelectedItems != null)
{
SelectedItems.Clear();
foreach (ListViewItem lvi in smartListView1.SelectedItems)
{
SelectedItems.Add(DataSource[Convert.ToInt32(lvi.Text)-1]);
}
}
DialogResult = DialogResult.OK;
}
private void btnCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
private void smartListView1_DoubleClick(object sender, EventArgs e)
{
SelectedItems.Clear();
SelectedItems.Add(DataSource[Convert.ToInt32(smartListView1.SelectedItems[0].Text)-1]);
DialogResult = DialogResult.OK;
}
#endregion
}
}