Reputation: 26929
I have a listview like this and in FormLoad event I should do some initializations for it such as this: ( I need these ) .
listView.Scrollable = true;
listView.HideSelection = false;
listView.FullRowSelect = true;
listView.View = View.Details;
listView.HeaderStyle = ColumnHeaderStyle.None;
ColumnHeader header = new ColumnHeader();
header.Text = "MyHdr";
header.Name = "MyCol";
header.Width = listView.ClientSize.Width;
listView.Columns.Add(header);
and the way I am adding items to it is pretty simple like this:
listView.Items.Add("hello");
listView.Items.Add("How are you");
//... etc
But I want them to be added and sorted alphabetically but when I add a new item to it and call Sort method, it doesn't do anything. Why?! :(
EDIT: This is the whole section that at its last line I am calling Sort() The goal is to have two list views, and a Move Button, when Move button is clicked the selected items from one listview should get moved to the other listview. (Both listviews don't need to be sorted. Just the AvailLV listview should be sorted )
private void MoveBtn_Click(object sender, EventArgs e)
{
ListView source=null;
ListView target= null;
if(AvailableLV.SelectedItems.Count>0)
{
source = AvailableLV;
target = SelectedLV;
}
if(SelectedLV.SelectedItems.Count>0)
{
source = SelectedLV;
target = AvailableLV;
}
if (source != null && target != null)
{
HaulItems(source, target);
}
}
private void HaulItems(ListView source , ListView target)
{
foreach(ListViewItem item in source.Items)
{
if(item.Selected)
{
source.Items.Remove(item);
target.Items.Add(item);
}
}
AvailableLV.Sort();
}
Upvotes: 2
Views: 27877
Reputation: 1
If you are only looking for a one-time sort and you have access to the data before it is added to the ListView then this is a tidy solution:
string[] exampleData = { "1", "2", "3" };
string[] namesToSortBy = { "Sam", "Bill", "Jeff" };
SortedList<string, ListViewItem> alphabetical = new SortedList<string, ListViewItem>();
for (int i = 0; i < exampleData.Length; i++)
{
ListViewItem lvi = new ListViewItem();
lvi.Text = exampleData[i];
lvi.SubItems.Add(namesToSortBy[i]);
alphabetical.Add(namesToSortBy[i], lvi);
}
foreach (KeyValuePair<string, ListViewItem> item in alphabetical)
{
listView1.Items.Add(item.Value);
}
Upvotes: 0
Reputation: 54453
Yet another later-comer to the ball-game.
This solution uses Linq
to sort the items.
It can sort by clicking the column headers. The sort is by numbers, strings or dates, it will toggle between ascending and descending and it ignores invalid data, sorting them to the beginning or end.
You need to feed in the types of the columns in a simple string.
static class LvHelper
{
public static void SortByColumn(this ListView lv, string colTypes,
ColumnClickEventArgs e)
{
string lvSort = "As0";
if (lv.Tag != null) lvSort = lv.Tag.ToString();
if (e.Column < 0 || e.Column > colTypes.Length - 1) return;
char sortType = colTypes[e.Column];
if (sortType == '-') return;
int mini = lv.Items.Cast<ListViewItem>().Select(x => x.SubItems.Count).Min();
if (sortType != 's' && lv.Items.Cast<ListViewItem>()
.Select(x => x.SubItems.Count - 1).Min() < e.Column) return;
int sortCol = Convert.ToInt32(lvSort.Substring(2));
bool asc = lvSort[0] == 'A';
if (e.Column == sortCol) asc = !asc;
DateTime dummyD;
double dummyN;
double maxDate = DateTime.MaxValue.ToOADate();
int order = asc ? 1 : -1;
List<ListViewItem> sorted = null;
try
{
if (sortType == 'n') // numbers
sorted = lv.Items.Cast<ListViewItem>().Select(x => x)
.OrderBy(x => order * Convert.ToDouble(
double.TryParse(x.SubItems[e.Column].Text, out dummyN)
? x.SubItems[e.Column].Text
: (double.MinValue / 2).ToString())).ToList();
else if (sortType == 'd') // dates
sorted = lv.Items.Cast<ListViewItem>().Select(x => x)
.OrderBy(x => (Convert.ToDateTime(
DateTime.TryParse(x.SubItems[e.Column].Text, out dummyD)
? x.SubItems[e.Column].Text
: "1900-01-01").ToOADate() * order)).ToList();
else // strings
{
if (asc)
sorted = lv.Items.Cast<ListViewItem>().Select(x => x)
.OrderBy(x => x.SubItems.Count -1 < e.Column
? "" : (x.SubItems[e.Column].Text)).ToList();
else sorted = lv.Items.Cast<ListViewItem>().Select(x => x)
.OrderByDescending(x => x.SubItems.Count -1 < e.Column
? "" : (x.SubItems[e.Column].Text)).ToList();
}
}
catch (ArgumentOutOfRangeException ex) { return; }
lv.Items.Clear();
lv.Items.AddRange(sorted.ToArray());
lv.Tag = "" + (asc ? "A" : "D") + sortType.ToString() + e.Column;
}
}
The solution uses the LV's Tag
to remember the current sort.
The solution expects data to be there, so missing subitems will make the sort fail.
It is written as an extension method, so after adding the class you can call it on any ListView
:
private void someListView_ColumnClick(object sender, ColumnClickEventArgs e)
{
ListView lv = sender as ListView;
string colTypes = "sds-n"; // string, date, string, excluded, number
lv.SortByColumn(colTypes, e);
}
Upvotes: 1
Reputation: 348
If anyone pays attention to this topic, I found the easiest route is to send the listview to a datatable and create a dataview from it and then sort the dataview. After that dataview is sorted, create a temporary table and then push the rows back into the listview. Ex below.
public string SortOrder;
public string ItemSorted;
private void LSTHistory_ColumnClick(object sender, ColumnClickEventArgs e)
{
DataTable TempTable = new DataTable();
for (int i = 0; i < LSTHistory.Columns.Count; i++)
{
TempTable.Columns.Add(LSTHistory.Columns[i].Text);
}
foreach (ListViewItem Item in LSTHistory.Items)
{
DataRow iRow = TempTable.NewRow();
iRow[0] = Item.Text;
iRow[1] = Item.SubItems[1].Text;
TempTable.Rows.Add(iRow);
}
if (SortOrder == string.Empty || SortOrder == "ASC") SortOrder = "DESC";
else SortOrder = "ASC";
if (e.Column == COLTime.Index)
{
ItemSorted = COLTime.Text;
}
else
{
ItemSorted = COLURL.Text;
}
DataView OldView = TempTable.DefaultView;
OldView.Sort = ItemSorted + " " + SortOrder;
DataTable SortedTable = OldView.ToTable();
LSTHistory.Items.Clear();
foreach (DataRow iRow in SortedTable.Rows)
{
LSTHistory.Items.Add(iRow[0].ToString()).SubItems.Add(iRow[1].ToString());
}
}
Upvotes: 1
Reputation: 54562
Where are you setting your ListView.Sorting Property
From above link:
The Sorting property allows you to specify whether or not items are sorted in the ListView control. By default, no sorting is performed. When the Sorting property is set to Ascending or Descending, the items in the ListView are sorted automatically in ascending alphabetical order (when the property is set to Ascending) or descending alphabetical order (when the property is set to Descending). You can use this property to automatically sort items that are displayed in your ListView control to make it easier for users to find items when a large number of items are available.
Looking at your edit, I think all you need to do is set the ListView.Sorting
Property on AvailableLV
and it will automatically sort your items as they are added. or instead of calling.
AvailableLV.Sort();
use
AvailableLV.Sorting = SortOrder.Ascending;
Upvotes: 6