[英]Sort ListView Columns on Just in-Time Data loading
I have populated a listview by Just In Time Data loading according to https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/virtual-mode-with-just-in-time-data-loading-in-the-datagrid我根据https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/virtual-mode-with-just-in-time-data-loading通过实时数据加载填充了一个列表视图数据网格中
and和
https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/implementing-virtual-mode-jit-data-loading-in-the-datagrid https://docs.microsoft.com/en-us/dotnet/framework/winforms/controls/implementing-virtual-mode-jit-data-loading-in-the-datagrid
Now I want to sort on columnClick of list view .现在我想对 list view 的 columnClick 进行排序。 I don't have any clue how should I do that我不知道我该怎么做
I have done like this Cache Class我已经完成了这个缓存类
public class Cache
{
private static int RowsPerPage;
// Represents one page of data.
public struct DataPage
{
public DataTable table;
private int lowestIndexValue;
private int highestIndexValue;
public DataPage(DataTable table, int rowIndex)
{
this.table = table;
lowestIndexValue = MapToLowerBoundary(rowIndex);
highestIndexValue = MapToUpperBoundary(rowIndex);
System.Diagnostics.Debug.Assert(lowestIndexValue >= 0);
System.Diagnostics.Debug.Assert(highestIndexValue >= 0);
}
public int LowestIndex
{
get
{
return lowestIndexValue;
}
}
public int HighestIndex
{
get
{
return highestIndexValue;
}
}
public static int MapToLowerBoundary(int rowIndex)
{
// Return the lowest index of a page containing the given index.
return (rowIndex / RowsPerPage) * RowsPerPage;
}
private static int MapToUpperBoundary(int rowIndex)
{
// Return the highest index of a page containing the given index.
return MapToLowerBoundary(rowIndex) + RowsPerPage - 1;
}
}
private DataPage[] cachePages;
private IDataPageRetriever dataSupply;
public Cache(IDataPageRetriever dataSupplier, int rowsPerPage)
{
dataSupply = dataSupplier;
Cache.RowsPerPage = rowsPerPage;
LoadFirstTwoPages();
}
public IDataPageRetriever DataSupplier
{
get
{
return dataSupply;
}
}
// Sets the value of the element parameter if the value is in the cache.
private bool IfPageCached_ThenSetElement(int rowIndex,
int columnIndex, ref object element)
{
if (IsRowCachedInPage(0, rowIndex))
{
element = cachePages[0].table
.Rows[rowIndex % RowsPerPage][columnIndex];
return true;
}
else if (IsRowCachedInPage(1, rowIndex))
{
element = cachePages[1].table
.Rows[rowIndex % RowsPerPage][columnIndex];
return true;
}
return false;
}
private bool IfPageCached_ThenSetElement(int rowIndex,
string columnName, ref object element)
{
if (IsRowCachedInPage(0, rowIndex))
{
element = cachePages[0].table
.Rows[rowIndex % RowsPerPage][columnName];
return true;
}
else if (IsRowCachedInPage(1, rowIndex))
{
element = cachePages[1].table
.Rows[rowIndex % RowsPerPage][columnName];
return true;
}
return false;
}
public object RetrieveElement(int rowIndex, int columnIndex)
{
object element = null;
if (IfPageCached_ThenSetElement(rowIndex, columnIndex, ref element))
{
return element;
}
else
{
return RetrieveData_CacheIt_ThenReturnElement(
rowIndex, columnIndex);
}
}
public object RetrieveElement(int rowIndex, string columnName)
{
object element = null;
if (IfPageCached_ThenSetElement(rowIndex, columnName, ref element))
{
return element;
}
else
{
return RetrieveData_CacheIt_ThenReturnElement(
rowIndex, columnName);
}
}
public void RemoveElement(int rowIndex)
{
if (IsRowCachedInPage(0, rowIndex))
{
cachePages[0].table.Rows.RemoveAt(rowIndex % RowsPerPage);
}
else if (IsRowCachedInPage(1, rowIndex))
{
cachePages[1].table.Rows.RemoveAt(rowIndex % RowsPerPage);
}
}
private void LoadFirstTwoPages()
{
cachePages = new DataPage[]{
new DataPage(dataSupply.SupplyPageOfData(
DataPage.MapToLowerBoundary(0), RowsPerPage), 0),
new DataPage(dataSupply.SupplyPageOfData(
DataPage.MapToLowerBoundary(RowsPerPage),
RowsPerPage), RowsPerPage)};
}
private object RetrieveData_CacheIt_ThenReturnElement(
int rowIndex, int columnIndex)
{
// Retrieve a page worth of data containing the requested value.
DataTable table = dataSupply.SupplyPageOfData(
DataPage.MapToLowerBoundary(rowIndex), RowsPerPage);
// Replace the cached page furthest from the requested cell
// with a new page containing the newly retrieved data.
cachePages[GetIndexToUnusedPage(rowIndex)] = new DataPage(table, rowIndex);
return RetrieveElement(rowIndex, columnIndex);
}
private object RetrieveData_CacheIt_ThenReturnElement(
int rowIndex, string columnName)
{
// Retrieve a page worth of data containing the requested value.
DataTable table = dataSupply.SupplyPageOfData(
DataPage.MapToLowerBoundary(rowIndex), RowsPerPage);
// Replace the cached page furthest from the requested cell
// with a new page containing the newly retrieved data.
cachePages[GetIndexToUnusedPage(rowIndex)] = new DataPage(table, rowIndex);
return RetrieveElement(rowIndex, columnName);
}
// Returns the index of the cached page most distant from the given index
// and therefore least likely to be reused.
private int GetIndexToUnusedPage(int rowIndex)
{
if (rowIndex > cachePages[0].HighestIndex &&
rowIndex > cachePages[1].HighestIndex)
{
int offsetFromPage0 = rowIndex - cachePages[0].HighestIndex;
int offsetFromPage1 = rowIndex - cachePages[1].HighestIndex;
if (offsetFromPage0 < offsetFromPage1)
{
return 1;
}
return 0;
}
else
{
int offsetFromPage0 = cachePages[0].LowestIndex - rowIndex;
int offsetFromPage1 = cachePages[1].LowestIndex - rowIndex;
if (offsetFromPage0 < offsetFromPage1)
{
return 1;
}
return 0;
}
}
// Returns a value indicating whether the given row index is contained
// in the given DataPage.
private bool IsRowCachedInPage(int pageNumber, int rowIndex)
{
return rowIndex <= cachePages[pageNumber].HighestIndex &&
rowIndex >= cachePages[pageNumber].LowestIndex;
}
}
And this is the DataRetriever:这是 DataRetriever:
public class DataRetriever : IDataPageRetriever
{
private string tableName;
private string whereClause;
private KeyValuePair<string, object>[] parameters;
public DataRetriever(string tableName, DataTable tableSchema, string whereClause, KeyValuePair<string, object>[] parameters)
{
this.tableName = tableName;
this.whereClause = whereClause;
this.parameters = parameters;
this.tableSchema = tableSchema;
}
private int rowCountValue = -1;
private DataTable tableSchema;
public int RowCount
{
get
{
// Return the existing value if it has already been determined.
if (rowCountValue != -1)
{
return rowCountValue;
}
StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM " + tableName);
if (!string.IsNullOrEmpty(whereClause))
sql.Append(" WHERE " + whereClause);
// Retrieve the row count from the database.
using (ECartableServiceClient client = new ECartableServiceClient())
{
rowCountValue = client.GetRowCount(sql.ToString(), parameters);
client.Close();
}
return rowCountValue;
}
}
private DataColumnCollection columnsValue;
public DataColumnCollection Columns
{
get
{
if (columnsValue == null)
{
if (tableSchema == null)
{
// Retrieve the column information from the database.
using (ECartableServiceClient client = new ECartableServiceClient())
{
columnsValue = client.GetTableSchema("SELECT * FROM " + tableName).Columns;
client.Close();
}
}
else
columnsValue = tableSchema.Columns;
}
return columnsValue;
}
}
private string commaSeparatedListOfColumnNamesValue = null;
private string CommaSeparatedListOfColumnNames
{
get
{
// Return the existing value if it has already been determined.
if (commaSeparatedListOfColumnNamesValue != null)
{
return commaSeparatedListOfColumnNamesValue;
}
// Store a list of column names for use in the
// SupplyPageOfData method.
System.Text.StringBuilder commaSeparatedColumnNames =
new System.Text.StringBuilder();
bool firstColumn = true;
foreach (DataColumn column in Columns)
{
if (!firstColumn)
{
commaSeparatedColumnNames.Append(", ");
}
commaSeparatedColumnNames.Append(column.ColumnName);
firstColumn = false;
}
commaSeparatedListOfColumnNamesValue =
commaSeparatedColumnNames.ToString();
return commaSeparatedListOfColumnNamesValue;
}
}
// Declare variables to be reused by the SupplyPageOfData method.
private string columnToSortBy;
public DataTable SupplyPageOfData(int lowerPageBoundary, int rowsPerPage)
{
// Store the name of the ID column. This column must contain unique
// values so the SQL below will work properly.
if (columnToSortBy == null)
{
columnToSortBy = this.Columns[0].ColumnName;
}
if (!this.Columns[columnToSortBy].Unique)
{
throw new InvalidOperationException(String.Format(
"Column {0} must contain unique values.", columnToSortBy));
}
// Retrieve the specified number of rows from the database, starting
// with the row specified by the lowerPageBoundary parameter.
DataTable table;
string sql = "declare @maxId int\n" +
"SELECT @maxId = MAX(" + columnToSortBy + ") FROM (SELECT TOP " + lowerPageBoundary + " " + columnToSortBy + " FROM " + tableName.Replace("*", "Id") + (string.IsNullOrEmpty(whereClause) ? "" : " WHERE " + whereClause) + " ORDER BY " + columnToSortBy + ") AS t2\n" +
"SELECT TOP " + rowsPerPage + " " +
CommaSeparatedListOfColumnNames + " FROM " + tableName +
" WHERE " + (string.IsNullOrEmpty(whereClause) ? "" : whereClause + " AND ") + columnToSortBy + " > case when @maxId is null then 0 else @maxId end ORDER BY " + columnToSortBy;
using (ECartableServiceClient client = new ECartableServiceClient())
{
table = client.GetDataTable(tableSchema, sql, parameters);
client.Close();
}
return table;
}
}
and this is what I do to call the data这就是我调用数据的方式
if (LoadData("vwUser", null, "Users", 50, searchCriteria, null))
ShowData("Users");
private bool LoadData(string tableName, DataTable tableSchema, string cacheName, int rowsPerPage, string criteria, KeyValuePair<string, object>[] parameters)
{
bool result = true;
object[] arguments = new object[6] { tableName, tableSchema, cacheName, rowsPerPage, criteria, parameters };
if (!dictionaryCaches.ContainsKey(cacheName))
{
try
{
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync(arguments);
formWait = new FormWait();
formWait.ShowDialog(this);
}
catch (System.Data.SqlClient.SqlException)
{
result = false;
MessageBox.Show("Connection could not be established. " +
"Verify that the connection string is valid.");
Application.Exit();
}
}
return result;
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event.
BackgroundWorker worker = sender as BackgroundWorker;
object[] arguments = (object[])e.Argument;
DataRetriever retriever =
new DataRetriever((string)arguments[0], (DataTable)arguments[1], (string)arguments[4], (KeyValuePair<string, object>[])arguments[5]); //"Date_Received >= @d", new KeyValuePair<string, object>[] { new KeyValuePair<string, object>("@d", DateTime.Today) });
dictionaryCaches.Add((string)arguments[2], new Cache(retriever, (int)arguments[3]));
int rowCount = retriever.RowCount;
}
how Can I sort the listView by ColumnCLick?如何通过 ColumnCLick 对 listView 进行排序?
Based on my test, I can not run your code successfully.根据我的测试,我无法成功运行您的代码。
However, I can use the following code to load the data in time and sort the listview by column click.但是,我可以使用以下代码及时加载数据并按列单击对列表视图进行排序。
Code:代码:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string connectionstring = @"connectionstring";
SqlConnection connection = new SqlConnection(connectionstring);
connection.Open();
string sql = "select * from Student";
SqlDataAdapter adapter = new SqlDataAdapter(sql,connection);
DataSet dataset = new DataSet();
adapter.Fill(dataset);
DataTable table = dataset.Tables[0];
List<string> list = new List<string>();
listView1.View = View.Details;
foreach (DataColumn item in table.Columns)
{
listView1.Columns.Add(item.ColumnName);
}
foreach (DataRow row in table.Rows)
{
ListViewItem listitem = new ListViewItem(row[0].ToString());
listitem.SubItems.Add(row[1].ToString());
listitem.SubItems.Add(row[2].ToString());
listView1.Items.Add(listitem);
}
}
private void listView1_ColumnClick(object sender, ColumnClickEventArgs e)
{
ListViewSorter Sorter = new ListViewSorter();
listView1.ListViewItemSorter = Sorter;
if (!(listView1.ListViewItemSorter is ListViewSorter))
return;
Sorter = (ListViewSorter)listView1.ListViewItemSorter;
if (Sorter.LastSort == e.Column)
{
if (listView1.Sorting == SortOrder.Ascending)
listView1.Sorting = SortOrder.Descending;
else
listView1.Sorting = SortOrder.Ascending;
}
else
{
listView1.Sorting = SortOrder.Descending;
}
Sorter.ByColumn = e.Column;
listView1.Sort();
}
}
public class ListViewSorter : System.Collections.IComparer
{
public int Compare(object o1, object o2)
{
if (!(o1 is ListViewItem))
return (0);
if (!(o2 is ListViewItem))
return (0);
ListViewItem lvi1 = (ListViewItem)o2;
string str1 = lvi1.SubItems[ByColumn].Text;
ListViewItem lvi2 = (ListViewItem)o1;
string str2 = lvi2.SubItems[ByColumn].Text;
int result;
if (lvi1.ListView.Sorting == SortOrder.Ascending)
result = String.Compare(str1, str2);
else
result = String.Compare(str2, str1);
LastSort = ByColumn;
return (result);
}
public int ByColumn
{
get
{
return Column;
}
set
{
Column = value;
}
}
int Column = 0;
public int LastSort
{
get
{
return LastColumn;
}
set
{
LastColumn = value;
}
}
int LastColumn = 0;
}
Result:结果:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.