简体   繁体   English

在实时数据加载时对 ListView 列进行排序

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM