Csharp/C#教程:C#DataGridView虚拟模式:启用排序分享


C#DataGridView虚拟模式:启用排序

有没有办法在虚拟模式下对DataGridView进行排序?

我在此微软示例之后以虚拟模式实现了Gridview: http : //msdn.microsoft.com/de-de/library/ms171624.aspx 。 我也修改了示例,以便能够将数据写入数据库。 这很好,虚拟模式可以大大提高速度,但我的客户需要对列进行排序。

在搜索网页一段时间后,我找到了链接https://social.msdn.microsoft.com/forums/en-US/winformsdatacontrols/thread/25b3f7c3-95b6-4c49-802b-b5a2a62915ac ,但无法获取工作。

有人能指出如果有办法在虚拟模式下对列进行排序,如果是这样,我将如何做到这一点?

非常感谢提前!

好的,我现在解决了这个问题。 使用microsoft示例( https://msdn.microsoft.com/de-de/library/ms171624.aspx )我修改了DataRetrieverLog类,以便在构造函数中接收一个额外的值:要排序的列名(包括排序)方向,例如“Name ASC”)。 对于任何感兴趣的人,这里是修改后的代码:

public class DataRetrieverLog : IDataPageRetriever { private string tableName; private string sortColumn; private SqlCommand command; private DataTable table; private SqlDataAdapter adapter; public DataRetrieverLog(string connectionString, string tableName, string sortColumn) { SqlConnection connection = new SqlConnection(connectionString); connection.Open(); command = connection.CreateCommand(); this.tableName = tableName; this.sortColumn = sortColumn; } private int rowCountValue = -1; public int RowCount { get { // Return the existing value if it has already been determined. if (rowCountValue != -1) { return rowCountValue; } // Retrieve the row count from the database. command.CommandText = "SELECT COUNT(*) FROM " + tableName; rowCountValue = (int)command.ExecuteScalar(); return rowCountValue; } } private DataColumnCollection columnsValue; public DataColumnCollection Columns { get { // Return the existing value if it has already been determined. if (columnsValue != null) { return columnsValue; } // Retrieve the column information from the database. command.CommandText = "SELECT * FROM " + tableName; SqlDataAdapter adapter = new SqlDataAdapter(); adapter.SelectCommand = command; DataTable table = new DataTable(); table.Locale = System.Globalization.CultureInfo.InvariantCulture; adapter.FillSchema(table, SchemaType.Source); columnsValue = table.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("], ["); } else { commaSeparatedColumnNames.Append("["); } commaSeparatedColumnNames.Append(column.ColumnName); firstColumn = false; } commaSeparatedColumnNames.Append("]"); 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. String text = "Select Top " + rowsPerPage + " " + CommaSeparatedListOfColumnNames + " From " + tableName + " WHERE " + columnToSortBy + " NOT IN (SELECT TOP " + lowerPageBoundary + " " + columnToSortBy + " From " + tableName + " Order By " + sortColumn + ") Order By " + sortColumn; command.CommandText = text; adapter = new SqlDataAdapter(text, GUI.dictSettings["connectionString"]); SqlCommandBuilder commandBuilder = new SqlCommandBuilder(adapter); table = new DataTable(); table.Locale = System.Globalization.CultureInfo.InvariantCulture; adapter.Fill(table); return table; } public DataTable getDataTable() { return table; } public SqlDataAdapter getAdapter() { return adapter; } } 

除此之外,我在Gridview中实现了ColumnHeaderMouseClick-Event。 在那里我得到列名和排序方向,然后通过创建一个新的DataRetrieverLog实例并传递列名+排序方向来重新加载所有基础表数据。 接下来我只刷新Gridview:gridView.Refresh()

而已。

编辑(20.07.2015):

为了使事情更清楚,这是在虚拟模式下使可排序的DataGridView工作的完整方法。 自从我玩这个游戏以来已经有一段时间了,所以我希望我能说清楚它让它工作并且没有错过任何事情。 要使其工作,需要三个助手类:

IDataPageRetriever.cs:

 using System.Data; using System.Data.SqlClient; namespace ASC.Code.Forms.Helper { public interface IDataPageRetriever { DataTable SupplyPageOfData(int lowerPageBoundary, int rowsPerPage); SqlDataAdapter getAdapter(); } } 

CacheAll.cs:

 using System.Data; using System.Data.SqlClient; namespace ASC.Code.Forms.Helper { public class CacheAll { private static int RowsPerPage; // Represents one page of data. public struct DataPage { public DataTable table; public SqlDataAdapter adapter; private int lowestIndexValue; private int highestIndexValue; public DataPage(DataTable table, SqlDataAdapter adapter, int rowIndex) { this.table = table; this.adapter = adapter; 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; } public DataTable getTable() { return this.table; } public SqlDataAdapter getAdapter() { return this.adapter; } } private DataPage[] cachePages; private IDataPageRetrieverAll dataSupply; public CacheAll(IDataPageRetrieverAll dataSupplier, int rowsPerPage) { dataSupply = dataSupplier; CacheAll.RowsPerPage = rowsPerPage; LoadFirstTwoPages(); } // Sets the value of the element parameter if the value is in the cache. private bool IfPageCached_ThenSetElement(int rowIndex, int columnIndex, ref string element) { if (IsRowCachedInPage(0, rowIndex)) { element = cachePages[0].table .Rows[rowIndex % RowsPerPage][columnIndex].ToString(); return true; } else if (cachePages.Length > 1) { if (IsRowCachedInPage(1, rowIndex)) { element = cachePages[1].table.Rows[rowIndex % RowsPerPage][columnIndex].ToString(); return true; } } return false; } public string RetrieveElement(int rowIndex, int columnIndex) { string element = null; if (IfPageCached_ThenSetElement(rowIndex, columnIndex, ref element)) { return element; } else { return RetrieveData_CacheIt_ThenReturnElement( rowIndex, columnIndex); } } private void LoadFirstTwoPages() { DataTable table1 = dataSupply.SupplyPageOfData(DataPage.MapToLowerBoundary(0), RowsPerPage); SqlDataAdapter adapter1 = dataSupply.getAdapter(); DataTable table2 = dataSupply.SupplyPageOfData(DataPage.MapToLowerBoundary(RowsPerPage), RowsPerPage); SqlDataAdapter adapter2 = dataSupply.getAdapter(); cachePages = new DataPage[]{ new DataPage(table1, adapter1, 0), new DataPage(table2, adapter2, RowsPerPage)}; } private string 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); SqlDataAdapter adapter = dataSupply.getAdapter(); // Replace the cached page furthest from the requested cell // with a new page containing the newly retrieved data. cachePages[GetIndexToUnusedPage(rowIndex)] = new DataPage(table, adapter, rowIndex); return RetrieveElement(rowIndex, columnIndex); } // 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; } public DataPage[] getCachePages() { return cachePages; } } } 

…和DataRetrieverAll.cs类:

 using System; using System.Data.SqlClient; using System.Data; namespace ASC.Code.Forms.Helper { public class DataRetrieverAll : IDataPageRetrieverAll { private string tableName; private string sortColumn; private SqlCommand command; private DataTable table; private SqlDataAdapter adapter; public DataRetrieverAll(string connectionString, string tableName, string sortColumn) { SqlConnection connection = new SqlConnection(connectionString); connection.Open(); command = connection.CreateCommand(); this.tableName = tableName; this.sortColumn = sortColumn; } private int rowCountValue = -1; public int RowCount { get { // Return the existing value if it has already been determined. if (rowCountValue != -1) { return rowCountValue; } // Retrieve the row count from the database. command.CommandText = "SELECT COUNT(*) FROM " + tableName; rowCountValue = (int)command.ExecuteScalar(); return rowCountValue; } } private DataColumnCollection columnsValue; public DataColumnCollection Columns { get { // Return the existing value if it has already been determined. if (columnsValue != null) { return columnsValue; } // Retrieve the column information from the database. command.CommandText = "SELECT * FROM " + tableName; SqlDataAdapter adapter = new SqlDataAdapter(); adapter.SelectCommand = command; DataTable table = new DataTable(); table.Locale = System.Globalization.CultureInfo.InvariantCulture; adapter.FillSchema(table, SchemaType.Source); columnsValue = table.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("], ["); } else { commaSeparatedColumnNames.Append("["); } commaSeparatedColumnNames.Append(column.ColumnName); firstColumn = false; } commaSeparatedColumnNames.Append("]"); 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. String text = "Select Top " + rowsPerPage + " " + CommaSeparatedListOfColumnNames + " From " + tableName + " WHERE " + columnToSortBy + " NOT IN (SELECT TOP " + lowerPageBoundary + " " + columnToSortBy + " From " + tableName + " Order By " + sortColumn + ") Order By " + sortColumn; command.CommandText = text; adapter = new SqlDataAdapter(text, GUI.dictSettings["connectionString"]); SqlCommandBuilder commandBuilder = new SqlCommandBuilder(adapter); table = new DataTable(); table.Locale = System.Globalization.CultureInfo.InvariantCulture; adapter.Fill(table); return table; } public DataTable getDataTable() { return table; } public SqlDataAdapter getAdapter() { return adapter; } } } 

那么,我如何填充网格? 我使用另一个Helper-Class并从Main GUI类调用Helper-Class中的方法:

Main.cs:

 //... private String columnToSortByAll; public GUI() { InitializeComponent(); init(); } private void init() { helper = new GUIHelper(grid, this); //Tabellen mit Werten füllen fillTablesInit(); } private void fillTablesInit() { helper.getData("(SELECT * FROM TOOL_materialSumme WHERE Display IS NULL OR Display = 1)a", "ID", asc_all); //asc_all = Boolean value, indicating sort direction asc /desc } private void grid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) { String columnName = grid.Columns[e.ColumnIndex].Name; if (columnName.Equals(columnToSortBy)) { if (asc_all) asc_all = false; else asc_all = true; } else { columnToSortBy = columnName; asc_all = true; } helper.getDataALL("(SELECT * FROM TOOL_materialSumme WHERE Display IS NULL OR Display = 1)a", columnToSortBy, asc_all); } private void grid_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) { String actualValue = helper.getMemoryCache().RetrieveElement(e.RowIndex, e.ColumnIndex); e.Value = actualValue; } private void grid_DataError(object sender, DataGridViewDataErrorEventArgs e) { //MessageBox.Show(e.Context.ToString()); } private void grid_CellValuePushed(object sender, DataGridViewCellValueEventArgs e) { String newValue = ""; if (e.Value != null) newValue = e.Value.ToString(); int column = e.ColumnIndex; ASC.Code.Forms.Helper.CacheAll.DataPage[] pages = helper.getMemoryCache().getCachePages(); DataTable[] tables = new DataTable[2]; SqlDataAdapter[] adapters = new SqlDataAdapter[2]; tables[0] = pages[0].getTable(); tables[1] = pages[1].getTable(); adapters[0] = pages[0].getAdapter(); adapters[1] = pages[1].getAdapter(); String id = grid.Rows[e.RowIndex].Cells["ID"].Value.ToString(); for (int x = 0; x < tables.Length; x++) { for (int a = 0; a < tables[x].Rows.Count; a++) { String temp = tables[x].Rows[a][column].ToString(); if (tables[x].Rows[a]["ID"].ToString() == id) { tables[x].Rows[a][column] = newValue; adapters[x].Update(tables[x]); break; } } } grid.Refresh(); } //... 

GUIHelper.cs:

 private DataGridView grid private CacheAll memoryCache; private DataRetrieverAll retriever; public GUIHelper(DataGridView grid, GUI gui) { this.gui = gui; this.grid = grid; init(); } private void init() { //... } public void getData(string selectCommand, string sortColumn, Boolean asc_all) { grid.VirtualMode = true; try { if (asc_all) sortColumn = "["+sortColumn + "] ASC"; else sortColumn = "["+sortColumn + "] DESC"; retriever = new DataRetrieverAll("Insert ConnectionString here...", selectCommand, sortColumn); memoryCache = new CacheAll(retriever, GUI.amountDatasets); //amountDatasets = Amount of Datasets per cached-page if (grid.Columns.Count == 0) { foreach (DataColumn column in retriever.Columns) { grid.Columns.Add(column.ColumnName, column.ColumnName); } } grid.Rows.Clear(); grid.RowCount = retriever.RowCount; grid.Refresh(); } catch (SqlException) { MessageBox.Show("Connection could not be established. " + "Verify that the connection string is valid."); Application.Exit(); } } public CacheAll getMemoryCache() { return memoryCacheAll; } 

嗯,这就是我做的方式,而且效果很好。 我最终没有使用它,但仍然有代码......设置grid.VirtualMode = true并为Main类中的网格实现ColumnHeaderMouseClick事件非常重要。 快乐的编码:-)

上述就是C#学习教程:C#DataGridView虚拟模式:启用排序分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注---计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/cdevelopment/955711.html

(0)
上一篇 2021年11月21日
下一篇 2021年11月21日

精彩推荐