WPF DataGrid Виртуализация столбцов

Я пытаюсь выполнить горизонтальную виртуализацию на моей DataGrid . Моя коллекция имеет тип:

   List<string[]>

который его длина первого измерения составляет 64, а второй примерно 5000

Я использовал VirtualCollection Пола МакКлина для достижения вертикальной виртуализации

Мой IItemsProvider инкапсулирует Iterator, который возвращает элемент строки [], который представляет строку в моей таблице.

Мой ItemsProvider:

public class ArrayItemProvider<I,T> :IArrayItemProvider, IItemsProvider<T[]> where I : IList<T>
{      
    public int FetchCount()
    {
        return 64;
    }

    public IList<T[]> FetchRange(int startIndex, int count)
    {
        return _iterator.Skip(startIndex).Take(count).ToList();
    }
}  

Итератор:

 public class ArrayItemIterator<I, T> : IArrayItemIterator<T> where I : IList<T>
 {             
    public IEnumerator<T[]> GetEnumerator()
    {
        for (int i = 0; i < _arrayItemLength; i++)
        {
            T[] arr = new T[_extent];

            for (int j = 0; j < _extent; j++)
            {
                arr[j] = _items[j][i];
            }

            yield return arr;
        }
    }

    public int Extent 
    {
        get { return _extent; }
    }

    public void UpdateExtent(int extent)
    {
        _extent = extent;
    }
}

}

Подводя итог вышесказанному, я получаю элементы строки [] для определенного диапазона через VirtualCollection .

Сейчас я пытаюсь виртуализировать столбцы. Мои столбцы генерируются во время выполнения заданным экстентом, это делается в обратном вызове присоединенного свойства в статическом классе DataGridBuilderUtil.

CS:

   for (int i = 0; i < _iterator.Extent; i++)
   {
        _dataGrid.Columns.Add(CreateColumn(i));
   }

   private static DataGridColumn CreateColumn(int i)
   {
       var column = new DataGridTextColumn();
       column.Header = "View - " + (i + 1);
       column.Binding = new Binding("[" + i + "]");
       return column;
   }

в DataGridBuilderUtil я также присоединяю событие ScrollViewer ScrollChanged объекта DataGrid, когда изменяется горизонтальный экстент:

1) Я добавляю новую колонку.

2) Я обновляю экстент итераторов для размещения другого столбца.

3) Я повторно прокручиваю в ту же позицию по вертикали, это делает мой ItemsSource (VirtualCollection), который наследуется от IList, для запроса его индекса и повторного запроса текущей страницы (с помощью моего флага IsDefferedLoadPageRequired)

  private static void OnScrollChanged(object sender, ScrollChangedEventArgs e)
  {
      if(e.HorizontalChange > 0.0)
      {                
          // add column  (1)
         _dataGrid.Columns.Add(CreateColumn(_dataGrid.Columns.Count));              

          // Update the Extent  (2)
          _iterator.UpdateExtent(_dataGrid.Columns.Count);              

          // Makes the VirtualCollection request the current page again. (3)
          _collection.IsDefferedLoadPageRequired = true;                            
          _scrollViewer.ScrollToVerticalOffset(_scrollViewer.VerticalOffset);
       }
  }

Так что теперь внутри VirtualCollection

    public T this[int index]
    {
        get
        {
            ....
            int pageIndex = index / PageSize;
            RequestPage(pageIndex);                
            ....
        }             
     }

который запрашивает ItemsProvider:

    public IList<T[]> FetchRange(int startIndex, int count)
    {
        return _iterator.Skip(startIndex).Take(count).ToList();
    }

который запрашивает итератор, помните, что наш экстент был увеличен для размещения другого столбца.

    public IEnumerator<T[]> GetEnumerator()
    {
        for (int i = 0; i < _arrayItemLength; i++)
        {
            T[] arr = new T[_extent];

            for (int j = 0; j < _extent; j++)
            {
                arr[j] = _items[j][i];
            }

            yield return arr;
        }
    }

Так что теперь у меня есть строковые [] элементы, которые были увеличены. String[20] элементы теперь строковые [21] Моя горизонтальная виртуализация данных сработала.

Проблема в том, что мои ячейки связаны таким образом: (из метода CreateColumn выше)

 column.Binding = new Binding("[" + i + "]");

есть ошибка привязки, в каждой из ячеек в новом столбце (привязки в исходных столбцах, которые генерируются при загрузке коллекции, работают нормально:

      System.Windows.Data Error: 17 : Cannot get 'Item[]' value (type 'String') from '' (type 'String[]').     BindingExpression:Path=[20]; DataItem='String[]' (HashCode=32127640); 
      target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')      ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException: Specified argument was out of the range of  valid values. 
      Parameter name: index'

Я думаю, что это связано с тем, что, когда мой столбец создан, элемент массива для этой строки не содержит этот индекс, в качестве альтернативы я также попытался создать столбец после обновления массива.

это имело тот же результат.

Большой вопрос здесь, почему не работает Binding, и как обновить привязку?

Кроме того, я устанавливаю DataGrid.EnableColumnVirtualization = True, чтобы свести все это вместе (если бы связка работала).

Редактировать:

Iv'e также попытался создать столбец после обновления коллекции:

     _collection.LoadCompletedEvent += OnLoadCompleted; // VirualCollection event after page is loaded. 

    private static void OnLoadCompleted(object sender, EventArgs e)
    {
        _dataGrid.Columns.Add(CreateColumn(_dataGrid.Columns.Count));
    }

    private static void OnScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        if(e.HorizontalChange > 0.0)
        {                
            // Update the Extent
            _iterator.UpdateExtent(_dataGrid.Columns.Count+1);

            // Makes the VirtualCollection request the current page again.
            _collection.IsLoadPageRequired = true;                            
            _scrollViewer.ScrollToVerticalOffset(_scrollViewer.VerticalOffset);
        }
    }

OnLoadComplete возникает после того, как VirtualCollection перезагружает текущую страницу.

1 ответ

Было бы интересно узнать, возникает ли эта ошибка всегда или только когда вы начинаете прокрутку. Тогда привязка может запрашивать индекс, который еще не доступен, поскольку вы еще не реализовали его в своей VirtualCollection.

Хотя, если честно, я чувствую, что вы используете неверный синтаксис пути привязки с индексаторами.

Посмотрите на эти ссылки:

http://msdn.microsoft.com/en-us/library/ms742451.aspx

http://msdn.microsoft.com/en-us/library/system.windows.data.binding.path.aspx

Как пример:

<Binding Path="[key]" .../>

Ключ должен быть либо типизированным индексом словаря или хеш-таблицы, либо целочисленным индексом массива. Кроме того, значение ключа должно быть типом, который напрямую привязывается к свойству, к которому он применяется. Например, хеш-таблица, содержащая строковые ключи и строковые значения, может быть использована таким образом для привязки к Text для TextBox.

Это означает, что если ваш индексатор имеет тип integer, вам понадобится что-то подобное в вашем XAML.

<Binding Path="[(sys:Int32)42,(sys:Int32)24]"... />

Я не уверен, почему вы создаете привязку вручную. Вы могли бы сделать это в xaml, не так ли?:)

Другие вопросы по тегам