Виртуальный режим DataGridView с простым списком в качестве источника

ранее я задал вопрос о производительности моего dataGridView из-за того, что он отображает большое количество строк, которые добавляются на основе входящего потока. Было дано несколько решений, одно из которых включало виртуальный режим. В MSDN есть статья по этому вопросу, но она кажется более сложной, чем мне нужно, поскольку она использует базу данных и редактируемое поле. Мой datagridview является только для отображения и данных дисплей помещается в список.

после того, как я принял ответ, который я получена эта ссылка: http://www.codeproject.com/Articles/23937/Paging-Data-with-DataGridView-in-VirtualMode . Даже если это использует пример базы данных, он лучше подходит для того, что мне нужно. Мой список, который будет содержать данные, которые я хочу отобразить, объявлен следующим образом:

List<ResultRow> captureResults = new List<ResultRow>();

объект ResultRow определяется следующим образом:

/* Simplified */
public class ResultRow
{
    private int first = 0;
    private string second = "";
    private UInt64 third = 0;
    private IPAddress fourth = null;
    /* etc */

    public ResultRow()
    {
    }

    public void Set (<the values>) //In actuallity a KeyValuePair
    {
        //field gets set here
    }

    public UInt64 Third
    {
        get { return third; }
        set { third = value; }
    }

    /* etc. */

}

после статьи, упомянутой выше, я создал ResultRowCache. Объект выполнен как следует:

/* Page size set to 100. */
ResultRowCache _cache   = new ResultRowCache(PAGE_SIZE, captureResults);

на моем событии загрузки формы я делаю следующее (связано с этой проблемой. Я также добавил обработчик событий, хотя это сделано с помощью IDE, поэтому непосредственно не отображается в этом коде. Определение ниже!)):

dataGrid.VirtualMode = true;

_cache = new ResultRowCache(PAGE_SIZE, captureResults);

dataGrid.Columns.Add("FirstColumn"  , "First column header");
dataGrid.Columns.Add("Second Column", "Second column header");
/* Etc. Adding all columns. (Every member or ResultRow has it's own column. */

dataGrid.RowCount = (int)_cache.TotalCount;

мне интересно, как здесь инициализируется счет строк. Вероятно, это 0 (из-за вызова конструктора ResultRowCache (см. ниже)), но он никогда не изменяется снова. Это назначение считается ссылкой? Как itupdate себя?

во всяком случае, вперед с тем, что у меня есть, ResultRowCache определяется следующим образом:

public class ResultRowCache
{
    public int  PageSize    = 100;
    public long TotalCount;
    public List<ResultRow> CachedData = null;
    private List<ResultRow> FullData;

    int _lastRowIndex = -1;

    public ResultRowCache (int pageSize, List<ResultRow> total)
    {
        PageSize = pageSize;
        FullData = total;

        LoadPage( 0 );
    }

    public void LoadPage (int rowIndex)
    {
         int lastRowIndex = rowIndex - ( rowIndex % PageSize );

         /* Page already loaded */
         if( lastRowIndex == _lastRowIndex ) return;

         /* New page */
         _lastRowIndex = lastRowIndex;

         /* Create a new cashes data object */
         if( CachedData == null ) CachedData = new List<ResultRow>();

         /* If cached data already existed, clear */
         CachedData.Clear();

         /* The index is valid (there is data */
         if (lastRowIndex < FullData.Count)
         {
             /* Not a full page */
             if (lastRowIndex + PageSize > FullData.Count)
             {
                 CachedData = FullData.GetRange(lastRowIndex, ((lastRowIndex + PageSize) - 1) - FullData.Count);

             }
            /* Full page */
            else
            {
                CachedData = FullData.GetRange(lastRowIndex, PageSize);
            }
        }

        TotalCount = CachedData.Count;
    }
    }
}

наконец, мое событие CellValueNeeded для datagrid определяется следующим образом:

void DataGridCellValueNeededEvent(object sender, DataGridViewCellValueEventArgs e)
{
    _cache.LoadPage(e.RowIndex);

    int rowIndex = e.RowIndex % _cache.PageSize;

    switch (dataGrid.Columns[e.ColumnIndex].Name)
    {
        /* Not actual names, example */
    case "FirstColumn":   e.Value = _cache.CachedData[rowIndex].First;  break;
        case "SecondColumn":  e.Value = _cache.CachedData[rowIndex].Second; break;
        /* Rest of the possibly columns/ResultRow values */
    }
}

проблема: мой datagrid остается пустым, даже если список "captureResults" заполняется. Вот что я пробовал до сих пор:

  • обновите элемент RowCount datagrid после коммутатора в событии.
  • объявить список с общей количество результатов в кэше, чтобы убедиться, что он всегда в актуальном состоянии. (Я боялся ,что" внешние модификации " не пройдут через список, который я передал в кэшированном конструкторе, даже если это была ссылка. (Довольно новый с C#))
  • установите для счета строк datagrid значение 100 (жесткое значение) в событии загрузки формы.
  • добавлен вызов "Update ()" в datagrid после добавления чего-либо в список captureResults. (это происходит из специального потока, который вызывает функцию это добавляет что-то в список)

ничего из вышеперечисленного не изменилось. Сетка остается пустой. Мне кажется, я упускаю нечто совершенно очевидное. Есть предложения?

-edit-добавлено что-то, что я пытался заставить его работать.

1 ответов


Я чувствую, что использование кэша несколько усложняет процесс (хотя я чувствую ответственность после отправки Вам ссылки на msdn, которая реализуется таким образом).

что я бы рекомендовал в качестве отправной точки:

  1. выбросьте кэш (это может быть полезно позже, если у вас возникнут проблемы с памятью, но пока давайте просто заполним ваш datagrid)

  2. хранить List<ResultsRow> в экземпляре переменная.

  3. обеспечить dataGrid.VirtualMode = true; (или equivilant)

  4. реализовать CellValueNeeded следующим образом:

        private void gridContacts_CellValueNeeded(object sender,  DataGridViewCellValueEventArgs e)
        {
           ResultRow dataObject = resultRows[e.RowIndex];
    
           switch(e.ColumnIndex)
           {
               case 0:
                   e.Value = dataObject.First;
                   break;
               case 1 :
                   e.Value = dataObject.Second;
                   break;
               //etc..
           }
        }
    

Примечание: вам нужно будет предоставить некоторые дополнительные общедоступные свойства в DataObject, чтобы их можно было установить в качестве значений в методе.

посмотрите, как вы справляетесь с этим. Если вы установите некоторые точки останова в методе CellValueNeeded, которые должны помочь в отладке любого дальнейшего неожиданного поведения. Удача.