我正在尝试优化我的速度过慢的 DataGridView,它使用 SQLite 数据库来使用虚拟模式和缓存获取数据,我已经使用了双缓冲的技巧并删除了列和行的自动调整大小。然而,尽管阅读了这个:http: //msdn.microsoft.com/en-us/library/ha5xt0d9.aspx 和那个:http: //msdn.microsoft.com/en-us/library/ha5xt0d9.aspx
我的网格非常慢,实际上对数据库的查询非常快,但似乎 DataGridView 的绘制速度非常慢,即使数据已经通过缓存加载...
但也许我的 Cache 类不是那么好,所以我想知道我是否做错了什么。原理很简单,一个Cache分为3个部分:Upper、Current(也可以称为“Middle”和Lower),每个部分由索引(start & end)分隔,如果已经加载了数据,Cache会给出根据那些非常简单的规则的值:
- 如果值在当前部分没问题,只需加载数据
- 如果需要的值是在上还是下,没有问题,这部分成为当前部分,只需要一个新部分。
IE
上部分:0 - 100 当前部分:101 - 201 下部分:202 - 302
需要的值在 Lower Part 之内,没有问题,Current 变为 Lower,Upper 变为 Current,只需要重新加载新的 Lower Part。显然,如果需要的值具有缓存不可用的行索引,则重新加载该值。
public class Cache
{
    private Dictionary<PagePart, Page> _pages;
    public Dictionary<PagePart, Page> Pages
    {
        get { return this._pages; }
        set { this._pages = value; }
    }
    private String _tableName;
    public String TableName
    {
        get { return this._tableName; }
        set { this._tableName = value; }
    }
    private SQLiteConnection _connection;
    public SQLiteConnection Connection
    {
        get { return this._connection; }
        set { this._connection = value; }
    }
    public Cache(String tableName, SQLiteConnection connection)
    {
        this.Connection = connection;
        this.TableName = tableName;
        this.Pages = new Dictionary<PagePart, Page>(PageNumber);
        IndexRange indexRangeUpper = new IndexRange(0, PageSize);
        IndexRange indexRangeCurrent = new IndexRange(PageSize + 1, 2 * PageSize);
        IndexRange indexRangeLower = new IndexRange(2 * PageSize + 1, 3 * PageSize);
        DataTable dataTableUpper = this.GetDataTableFromTable(indexRangeUpper);
        DataTable dataTableCurrent = this.GetDataTableFromTable(indexRangeCurrent);
        DataTable dataTableLower = this.GetDataTableFromTable(indexRangeLower);
        Page pageUpper = new Page(indexRangeUpper, dataTableUpper);
        Page pageCurrent = new Page(indexRangeCurrent, dataTableCurrent);
        Page pageLower = new Page(indexRangeLower, dataTableLower);
        Pages.Add(PagePart.Upper, pageUpper);
        Pages.Add(PagePart.Current, pageCurrent);
        Pages.Add(PagePart.Lower, pageLower);
    }
    private IndexRange GetTableIndexRange()
    {
        String commandText = String.Format("SELECT MAX(RowId) FROM {0}", this.TableName);
        SQLiteCommand command = new SQLiteCommand(commandText, this.Connection);
        this.Connection.Open();
        command.CommandText = commandText;
        String maxRowIdString = command.ExecuteScalar().ToString();
        this.Connection.Close();
        Int32 maxRowId = Int32.Parse(maxRowIdString);
        return new IndexRange(0, maxRowId);
    }
    public Object GetCellValue(Int32 rowIndex, Int32 columnIndex)
    {
        Int32 indexLowerStart = Pages[PagePart.Lower].Range.StartIndex;
        Int32 indexLowerEnd = Pages[PagePart.Lower].Range.EndIndex;
        Int32 indexCurrentStart = Pages[PagePart.Current].Range.StartIndex;
        Int32 indexCurrentEnd = Pages[PagePart.Current].Range.EndIndex;
        Int32 indexUpperStart = Pages[PagePart.Upper].Range.StartIndex;
        Int32 indexUpperEnd = Pages[PagePart.Upper].Range.EndIndex;
        IndexRange indexRangeTable = this.GetTableIndexRange();
        Int32 indexTableStart = indexRangeTable.StartIndex;
        Int32 indexTableEnd = indexRangeTable.EndIndex;
        // Using the cache...
        if ((indexUpperStart <= rowIndex) && (rowIndex <= indexLowerEnd))
        {
            if ((indexLowerStart <= rowIndex) && (rowIndex <= indexLowerEnd))
            {
                if (indexTableEnd > indexLowerEnd)
                {
                    this.Pages[PagePart.Upper] = this.Pages[PagePart.Current];
                    this.Pages[PagePart.Current] = this.Pages[PagePart.Lower];
                    IndexRange indexRangeLower = new IndexRange(this.Pages[PagePart.Current].Range.EndIndex + 1, this.Pages[PagePart.Current].Range.EndIndex + PageSize);
                    DataTable dataTableLower = this.GetDataTableFromTable(indexRangeLower);
                    Page pageLower = new Page(indexRangeLower, dataTableLower);
                    this.Pages[PagePart.Lower] = pageLower;
                    Int32 pageSize = this.Pages[PagePart.Current].Data.Rows.Count;
                    return this.Pages[PagePart.Current].Data.Rows[rowIndex % pageSize][columnIndex];
                }
                else
                {
                    Int32 pageSize = this.Pages[PagePart.Lower].Data.Rows.Count;
                    return this.Pages[PagePart.Lower].Data.Rows[rowIndex % pageSize][columnIndex];
                }
            }
            if ((indexCurrentStart <= rowIndex) && (rowIndex <= indexCurrentEnd))
            {
                Int32 pageSize = this.Pages[PagePart.Current].Data.Rows.Count;
                return this.Pages[PagePart.Current].Data.Rows[rowIndex % pageSize][columnIndex];
            }
            if ((indexUpperStart <= rowIndex) && (rowIndex <= indexUpperEnd))
            {
                if (indexTableStart < indexUpperStart)
                {
                    this.Pages[PagePart.Lower] = this.Pages[PagePart.Current];
                    this.Pages[PagePart.Current] = this.Pages[PagePart.Upper];
                    IndexRange indexRangeUpper = new IndexRange(this.Pages[PagePart.Current].Range.StartIndex - 1, this.Pages[PagePart.Current].Range.EndIndex - PageSize);
                    DataTable dataTableUpper = this.GetDataTableFromTable(indexRangeUpper);
                    Page pageUpper = new Page(indexRangeUpper, dataTableUpper);
                    this.Pages[PagePart.Upper] = pageUpper;
                    Int32 pageSize = this.Pages[PagePart.Current].Data.Rows.Count;
                    return this.Pages[PagePart.Current].Data.Rows[rowIndex % pageSize][columnIndex];
                }
                else
                {
                    Int32 pageSize = this.Pages[PagePart.Upper].Data.Rows.Count;
                    return this.Pages[PagePart.Upper].Data.Rows[rowIndex % pageSize][columnIndex];
                }
            }
            return null;
        }
        // Need to reload the cache...
        else
        {
            IndexRange indexRangeCurrent = new IndexRange(rowIndex - (PageSize / 2), rowIndex + (PageSize / 2));
            IndexRange indexRangeLower = new IndexRange(indexRangeCurrent.EndIndex + 1, indexRangeCurrent.EndIndex + PageSize);
            IndexRange indexRangeUpper = new IndexRange(indexRangeCurrent.StartIndex - 1, indexRangeCurrent.StartIndex - PageSize );
            DataTable dataTableUpper = this.GetDataTableFromTable(indexRangeUpper);
            DataTable dataTableCurrent = this.GetDataTableFromTable(indexRangeCurrent);
            DataTable dataTableLower = this.GetDataTableFromTable(indexRangeLower);
            Page pageUpper = new Page(indexRangeUpper, dataTableUpper);
            Page pageCurrent = new Page(indexRangeCurrent, dataTableCurrent);
            Page pageLower = new Page(indexRangeLower, dataTableLower);
            Pages[PagePart.Upper] = pageUpper;
            Pages[PagePart.Current] = pageCurrent;
            Pages[PagePart.Lower] = pageLower;
            Int32 pageSize = this.Pages[PagePart.Current].Data.Rows.Count;
            return this.Pages[PagePart.Current].Data.Rows[rowIndex % pageSize][columnIndex];
        }
    }
    private DataTable GetDataTableFromTable(IndexRange indexRange)
    {
        if (this.Connection != null)
        {
            String commandText = String.Format("SELECT * FROM {0} WHERE RowId BETWEEN {1} AND {2}", this.TableName, indexRange.StartIndex, indexRange.EndIndex);
            SQLiteCommand command = new SQLiteCommand(commandText, this.Connection);
            SQLiteDataAdapter dataAdapter = new SQLiteDataAdapter(command);
            DataTable dataTable = new DataTable(this.TableName, this.TableName);
            dataAdapter.Fill(dataTable);
            return dataTable;
        }
        else
        {
            return null;
        }
    }
    private const Int32 PageNumber = 3;
    private const Int32 PageSize = 128;
    public class Page
    {
        public Page(IndexRange range, DataTable data)
        {
            this.Range = range;
            this.Data = data;
        }
        private IndexRange _range;
        public IndexRange Range
        {
            get { return this._range; }
            set { this._range = value; }
        }
        private DataTable _data;
        public DataTable Data
        {
            get { return this._data; }
            set { this._data = value; }
        }
    }
    public enum PagePart
    {
        Upper,
        Current,
        Lower,
    }
    public class IndexRange
    {
        private Int32 _startIndex;
        public Int32 StartIndex
        {
            get { return this._startIndex; }
            set { this._startIndex = value; }
        }
        private Int32 _endIndex;
        public Int32 EndIndex
        {
            get { return this._endIndex; }
            set { this._endIndex = value; }
        }
        public IndexRange(Int32 startIndex, Int32 stopIndex)
        {
            this.StartIndex = startIndex;
            this.EndIndex = stopIndex;
        }
    }
}
但是哎呀……画得太慢了……我该怎么办……?