Hi,
I see bugs everywhere, but this time I think I’m right (probably most of you has already discovered the problem).
I’m writing a C# program using Visual Studio 2005 Professional Edition, and I have prepared a class called ColumnSortedListView, that is a derivated class of ListView, with the possibility to order the ListView object by column.
The code is similar to the one proposed in the MSDN library (if you are interested, you can find my code below): the sorting is customized derivating the IComparer class (as MSDN library does in its example).
I have created a main class, called FormListView (derivated from Form), containing 1 ColumnSortedListView object and 2 buttons: the first called btnPopulateList, and the second called btnClearList (the btnPopulateList adds 1000 ListViewItem objects to the ListView, and the btnClearList clears the ListView, so you can see how much time the program spends to re-populate it).
When the program starts, the ListView is populated for the first time (not sorted respect to anyone of the columns).
If you click on a column header, the ListView is sorted respect to that column. From this moment (as the ListViewItemSorter property is set), if you click on btnClearList and then on btnPopulateList, the ListView is populated sorted respect to the column.
Well, the strange thing is this one:
if you populate the list without sorting (so until you click on a column header for the first time), the list is populated quickly; if you click on a column header, the list is sorted respect to that column quickly. At this point, if you click (first on btnClearList and then) on btnPopulateList, the list is populated (and sorted respect to that column at the same time) very very very slowly.
The obvious solution is: when I have to populate the ListView, before starting I assign the ListViewItemSorter to null (so that the ListView is populated without sorting), and after finishing I call the SortColumn procedure (the same I call when the user clicks on a column header).
In this way the time the program spends to populate the ListView is short.
Isn’t it a bug for you? What do you think about?
Thank you
P.S.: The code is rather long, but I think simple; if anyone wants to try…
As the ColumnSortedListView has 3 columns (the first containing strings, the second integral numbers and the third dates, for precision I have written 3 classes derived from IComparer, that is ListViewItemDatesComparer, ListViewItemNumbersComparer and ListViewItemStringsComparer (in the SortColumn procedure I verify the type of the (first ListViewItem) SubItem relative to the column and assign the ListViewItemSorter to one of the three).
I see bugs everywhere, but this time I think I’m right (probably most of you has already discovered the problem).
I’m writing a C# program using Visual Studio 2005 Professional Edition, and I have prepared a class called ColumnSortedListView, that is a derivated class of ListView, with the possibility to order the ListView object by column.
The code is similar to the one proposed in the MSDN library (if you are interested, you can find my code below): the sorting is customized derivating the IComparer class (as MSDN library does in its example).
I have created a main class, called FormListView (derivated from Form), containing 1 ColumnSortedListView object and 2 buttons: the first called btnPopulateList, and the second called btnClearList (the btnPopulateList adds 1000 ListViewItem objects to the ListView, and the btnClearList clears the ListView, so you can see how much time the program spends to re-populate it).
When the program starts, the ListView is populated for the first time (not sorted respect to anyone of the columns).
If you click on a column header, the ListView is sorted respect to that column. From this moment (as the ListViewItemSorter property is set), if you click on btnClearList and then on btnPopulateList, the ListView is populated sorted respect to the column.
Well, the strange thing is this one:
if you populate the list without sorting (so until you click on a column header for the first time), the list is populated quickly; if you click on a column header, the list is sorted respect to that column quickly. At this point, if you click (first on btnClearList and then) on btnPopulateList, the list is populated (and sorted respect to that column at the same time) very very very slowly.
The obvious solution is: when I have to populate the ListView, before starting I assign the ListViewItemSorter to null (so that the ListView is populated without sorting), and after finishing I call the SortColumn procedure (the same I call when the user clicks on a column header).
In this way the time the program spends to populate the ListView is short.
Isn’t it a bug for you? What do you think about?
Thank you
P.S.: The code is rather long, but I think simple; if anyone wants to try…
As the ColumnSortedListView has 3 columns (the first containing strings, the second integral numbers and the third dates, for precision I have written 3 classes derived from IComparer, that is ListViewItemDatesComparer, ListViewItemNumbersComparer and ListViewItemStringsComparer (in the SortColumn procedure I verify the type of the (first ListViewItem) SubItem relative to the column and assign the ListViewItemSorter to one of the three).
Code:
using System;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;
class SeparateMain
{
public static void Main()
{
Application.Run(new FormListView());
}
}
class FormListView : Form
{
ColumnSortedListView cslvList;
Button btnClearList, btnPopulateList;
public FormListView()
{
this.Size = new Size(500, 500);
this.CenterToScreen();
cslvList = new ColumnSortedListView();
cslvList.Parent = this;
cslvList.Size = new Size(390, 400);
cslvList.Location = new Point(10, 10);
cslvList.View = View.Details;
cslvList.MultiSelect = true;
cslvList.FullRowSelect = true;
cslvList.HideSelection = false;
cslvList.Columns.Add("String", 120, HorizontalAlignment.Left);
cslvList.Columns.Add("Number", 120, HorizontalAlignment.Left);
cslvList.Columns.Add("Date", 120, HorizontalAlignment.Left);
btnClearList = new Button();
btnClearList.Parent = this;
btnClearList.Size = new Size(90, 20);
btnClearList.Location = new Point(40, 430);
btnClearList.Text = "Clear list";
btnClearList.Click += new EventHandler(btnClearList_Click);
btnPopulateList = new Button();
btnPopulateList.Parent = this;
btnPopulateList.Size = new Size(90, 20);
btnPopulateList.Location = new Point(150, 430);
btnPopulateList.Text = "Populate list";
btnPopulateList.Click += new EventHandler(btnPopulateList_Click);
PopulateList();
}
void btnClearList_Click(object sender, EventArgs e)
{
cslvList.Items.Clear();
}
void btnPopulateList_Click(object sender, EventArgs e)
{
PopulateList();
}
void PopulateList()
{
if (cslvList.Items.Count > 0)
MessageBox.Show("Clear the list before populating it", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
else
{
cslvList.LooseSorting();
cslvList.BeginUpdate();
for (int i = 0; i <= 1000; i++)
{
ListViewItem lvi = new ListViewItem("String" + i);
lvi.SubItems.Add(Convert.ToString(i));
lvi.SubItems.Add(Convert.ToString(new DateTime(2000, 1, 1) + new TimeSpan(i, 0, 0, 0)));
cslvList.Items.Add(lvi);
}
cslvList.EndUpdate();
if (cslvList.LastColSorted != -1)
cslvList.SortColumn(cslvList.LastColSorted, cslvList.LastColSortedOrder);
}
}
}
class ColumnSortedListView : ListView
{
public enum Order
{
Ascending,
Descending
}
private int lastColSorted;
private ColumnSortedListView.Order lastColSortedOrder;
public ColumnSortedListView()
{
lastColSorted = -1;
lastColSortedOrder = ColumnSortedListView.Order.Ascending;
}
public int LastColSorted
{
get
{
return lastColSorted;
}
}
public Order LastColSortedOrder
{
get
{
return lastColSortedOrder;
}
}
protected override void OnColumnClick(ColumnClickEventArgs e)
{
base.OnColumnClick (e);
if (lastColSorted != e.Column)
SortColumn(e.Column, ColumnSortedListView.Order.Ascending);
else
{
if (lastColSortedOrder == ColumnSortedListView.Order.Ascending)
SortColumn(e.Column, ColumnSortedListView.Order.Descending);
else // if (lastColSorted == ColumnSortedListView.Order.Descending)
SortColumn(e.Column, ColumnSortedListView.Order.Ascending);
}
}
public void SortColumn(int col, ColumnSortedListView.Order or)
{
if (Items.Count > 0)
{
ListViewItem lvi = Items[0];
String str = lvi.SubItems[col].Text;
try
{
DateTime dt = Convert.ToDateTime(str);
ListViewItemSorter = new ListViewItemDatesComparer(col, or);
Sort();
}
catch (Exception exNotDates)
{
try
{
int n = Convert.ToInt32(str);
ListViewItemSorter = new ListViewItemNumbersComparer(col, or);
Sort();
}
catch
{
ListViewItemSorter = new ListViewItemStringsComparer(col, or);
Sort();
}
}
}
lastColSorted = col;
lastColSortedOrder = or;
}
public void LooseSorting()
{
ListViewItemSorter = null;
}
}
class ListViewItemDatesComparer : IComparer
{
private int column;
private ColumnSortedListView.Order order;
public ListViewItemDatesComparer(int col, ColumnSortedListView.Order or)
{
column = col;
order = or;
}
public int Compare(object x, object y)
{
ListViewItem lvx = (ListViewItem)x;
ListViewItem lvy = (ListViewItem)y;
String strx = lvx.SubItems[column].Text;
String stry = lvy.SubItems[column].Text;
DateTime dx = Convert.ToDateTime(strx);
DateTime dy = Convert.ToDateTime(stry);
if (order == ColumnSortedListView.Order.Ascending)
{
if (dx < dy)
return -1;
else if (dx == dy)
return 0;
else
return 1;
}
else
{
if (dy < dx)
return -1;
else if (dy == dx)
return 0;
else
return 1;
}
}
}
class ListViewItemNumbersComparer : IComparer
{
private int column;
private ColumnSortedListView.Order order;
public ListViewItemNumbersComparer(int col, ColumnSortedListView.Order or)
{
column = col;
order = or;
}
public int Compare(object x, object y)
{
ListViewItem lvx = (ListViewItem)x;
ListViewItem lvy = (ListViewItem)y;
String strx = lvx.SubItems[column].Text;
String stry = lvy.SubItems[column].Text;
int ix = Convert.ToInt32(strx);
int iy = Convert.ToInt32(stry);
if (order == ColumnSortedListView.Order.Ascending)
{
if (ix < iy)
return -1;
else if (ix == iy)
return 0;
else
return 1;
}
else
{
if (iy < ix)
return -1;
else if (iy == ix)
return 0;
else
return 1;
}
}
}
class ListViewItemStringsComparer : IComparer
{
private int column;
private ColumnSortedListView.Order order;
public ListViewItemStringsComparer(int col, ColumnSortedListView.Order or)
{
column = col;
order = or;
}
public int Compare(object x, object y)
{
ListViewItem lvx = (ListViewItem)x;
ListViewItem lvy = (ListViewItem)y;
String strx = lvx.SubItems[column].Text;
String stry = lvy.SubItems[column].Text;
if (order == ColumnSortedListView.Order.Ascending)
return String.Compare(lvx.SubItems[column].Text, lvy.SubItems[column].Text);
else
return String.Compare(lvy.SubItems[column].Text, lvx.SubItems[column].Text);
}
}