Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#DataGridView虚拟模式:启用排序_C#_Sorting_Datagridview_Gridview Sorting_Virtualmode - Fatal编程技术网

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

C#DataGridView虚拟模式:启用排序,c#,sorting,datagridview,gridview-sorting,virtualmode,C#,Sorting,Datagridview,Gridview Sorting,Virtualmode,有没有办法在虚拟模式下对DataGridView进行排序 我已经按照以下microsoft示例在虚拟模式下实现了Gridview:。我还修改了这个示例,使其能够将数据写入数据库。这很好,虚拟模式可以极大地提高速度,但我的客户需要对列进行排序 在网上搜索了一段时间后,我找到了这个链接,但无法让它工作 有谁能指出,若有办法在虚拟模式下对列进行排序,若有,我该怎么做 提前多谢 好的,我现在已经解决了这个问题。使用microsoft示例()我修改了DataRetrieverLog类以在构造函数中接收一个

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

我已经按照以下microsoft示例在虚拟模式下实现了Gridview:。我还修改了这个示例,使其能够将数据写入数据库。这很好,虚拟模式可以极大地提高速度,但我的客户需要对列进行排序

在网上搜索了一段时间后,我找到了这个链接,但无法让它工作

有谁能指出,若有办法在虚拟模式下对列进行排序,若有,我该怎么做


提前多谢

好的,我现在已经解决了这个问题。使用microsoft示例()我修改了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事件。在这种情况下,我获取列名和排序方向,然后通过创建新的DataRetrieverLog实例并传递列名+排序方向来重新加载所有基础表数据。接下来我只刷新Gridview:Gridview.refresh()

就这样

编辑(2015年7月20日):

为了让事情更清楚一点,下面是让可排序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;
        }

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

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();
}
//...

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

我尝试按照您的指示使用虚拟模式进行排序。这是我的url。如果可能,请查看并回答如何实现我的目标。谢谢!对不起,迟了答复。过去几天我有很多事情要做。通过你的链接,我看到你已经解决了这个问题。很高兴我能提供帮助-以一种独立的方式提供我上面的代码:-)你能指导我如何在数据加载开始和网格填充结束时在前端引发事件吗。我喜欢在数据加载开始时引发两个事件,在网格数据加载结束时引发另一个事件。我需要你的帮助。谢谢!看看我上面的编辑。我想现在一切都应该解释清楚了。我已经有一段时间没有做这个了,所以我可能错过了一些细节——但你应该明白:-)哦,我想我误解了你的问题:在更改或编辑数据源之前和之后,你需要一个事件?嗯-那怎么样。。。和DataGridView.DataBindingComplete,在加载数据之后?
//...
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();
}
//...
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;
}