Виртуальный режим 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, которая реализуется таким образом).
что я бы рекомендовал в качестве отправной точки:
выбросьте кэш (это может быть полезно позже, если у вас возникнут проблемы с памятью, но пока давайте просто заполним ваш datagrid)
хранить
List<ResultsRow>
в экземпляре переменная.обеспечить
dataGrid.VirtualMode = true;
(или equivilant)-
реализовать 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, которые должны помочь в отладке любого дальнейшего неожиданного поведения. Удача.