我正在尝试在DataGrid上执行水平虚拟化。 我的收藏品类型为:
List<string[]>
它的第一个尺寸长度是64,第二个尺寸大约是5000
我一直在使用Paul McClean's VirtualCollection来实现垂直虚拟化
我的IItemsProvider封装了一个Iterator,它返回表示的string []的项目 在我的桌子上一排。
我的项目提供者:
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接收特定范围的字符串[]项。
我现在正在尝试的是对列进行Virtualaize, 我的列是在运行时由给定的Extent生成的,这是在附加属性的回调中完成的, 在静态类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中的我还附加了DataGrid的ScrollViewer ScrollChanged事件, 更改水平范围时:
1)我添加了一个新列。
2)我更新Iterators Extent以容纳另一列。
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();
}
查询Iterator,请记住我们的Extent已增加以容纳另一列。
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;
}
}
所以现在我有一个字符串[]项目,其中增加了字符串[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'
我认为这与我的列创建该行的数组项时的事实有关 不包含该索引,或者我也尝试在更新数组后创建列。
具有相同的结果。
这里最大的问题是,为什么不绑定工作,以及如何刷新绑定?
此外,我设置了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);
}
}
在VirtualCollection重新加载当前页面后引发OnLoadComplete。
答案 0 :(得分:0)
知道是否总是抛出该错误或仅在您开始滚动时才会感兴趣。然后绑定可能会要求索引不可用,因为你还没有在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]" .../>
key必须是字典或散列表的类型索引,或者是数组的整数索引。此外,键的值必须是可直接绑定到应用它的属性的类型。例如,包含字符串键和字符串值的哈希表可以使用这种方式绑定到TextBox的Text。
意味着如果你的索引器是整数类型,你需要在XAML中使用类似的东西。
<Binding Path="[(sys:Int32)42,(sys:Int32)24]"... />
我不确定为什么要手动创建绑定。你可以用xaml做到这一点,你呢? :)