C# WPF Listbox虚拟化创建DisconnectedItems
我正在尝试使用WPF列表框创建一个图形控件。我创建了我自己的画布,它源自虚拟化面板,我自己处理项目的实现和虚拟化 然后将listbox的“项目”面板设置为我的自定义虚拟画布 我遇到的问题发生在以下场景中:C# WPF Listbox虚拟化创建DisconnectedItems,c#,.net,wpf,virtualization,C#,.net,Wpf,Virtualization,我正在尝试使用WPF列表框创建一个图形控件。我创建了我自己的画布,它源自虚拟化面板,我自己处理项目的实现和虚拟化 然后将listbox的“项目”面板设置为我的自定义虚拟画布 我遇到的问题发生在以下场景中: 首先创建列表框项A ListBox项B在画布上的项A右侧创建 ListBox项A首先被虚拟化(通过在视图外平移它) ListBox项B第二次被虚拟化(再次通过将其平移到视图之外) 查看列表框项目A和B(即:实现它们) 使用Snoop,我检测到ListBox现在有3个项目,其中一个是位于Lis
- 首先创建列表框项A
- ListBox项B在画布上的项A右侧创建
- ListBox项A首先被虚拟化(通过在视图外平移它)
- ListBox项B第二次被虚拟化(再次通过将其平移到视图之外)
- 查看列表框项目A和B(即:实现它们)
- 使用Snoop,我检测到ListBox现在有3个项目,其中一个是位于ListBox项目B正下方的“DisconnectedItem”
/// <summary>
/// Arranges and virtualizes child element positionned explicitly.
/// </summary>
public class VirtualizingCanvas : VirtualizingPanel
{
(...)
protected override Size MeasureOverride(Size constraint)
{
ItemsControl itemsOwner = ItemsControl.GetItemsOwner(this);
// For some reason you have to "touch" the children collection in
// order for the ItemContainerGenerator to initialize properly.
var necessaryChidrenTouch = Children;
IItemContainerGenerator generator = ItemContainerGenerator;
IDisposable generationAction = null;
int index = 0;
Rect visibilityRect = new Rect(
-HorizontalOffset / ZoomFactor,
-VerticalOffset / ZoomFactor,
ActualWidth / ZoomFactor,
ActualHeight / ZoomFactor);
// Loop thru the list of items and generate their container
// if they are included in the current visible view.
foreach (object item in itemsOwner.Items)
{
var virtualizedItem = item as IVirtualizingCanvasItem;
if (virtualizedItem == null ||
visibilityRect.IntersectsWith(GetBounds(virtualizedItem)))
{
if (generationAction == null)
{
GeneratorPosition startPosition =
generator.GeneratorPositionFromIndex(index);
generationAction = generator.StartAt(startPosition,
GeneratorDirection.Forward, true);
}
GenerateItem(index);
}
else
{
GeneratorPosition itemPosition =
generator.GeneratorPositionFromIndex(index);
if (itemPosition.Index != -1 && itemPosition.Offset == 0)
{
RemoveInternalChildRange(index, 1);
generator.Remove(itemPosition, 1);
}
// The generator needs to be "reseted" when we skip some items
// in the sequence...
if (generationAction != null)
{
generationAction.Dispose();
generationAction = null;
}
}
++index;
}
if (generationAction != null)
{
generationAction.Dispose();
}
return default(Size);
}
(...)
private void GenerateItem(int index)
{
bool newlyRealized;
var element =
ItemContainerGenerator.GenerateNext(out newlyRealized) as UIElement;
if (newlyRealized)
{
if (index >= InternalChildren.Count)
{
AddInternalChild(element);
}
else
{
InsertInternalChild(index, element);
}
ItemContainerGenerator.PrepareItemContainer(element);
element.RenderTransform = _scaleTransform;
}
element.Measure(new Size(double.PositiveInfinity,
double.PositiveInfinity));
}
//
///安排并虚拟化显式定位的子元素。
///
公共类VirtualzingCanvas:VirtualzingPanel
{
(...)
受保护的覆盖尺寸测量覆盖(尺寸约束)
{
ItemsControl itemsOwner=ItemsControl.GetItemsOwner(此);
//出于某种原因,您必须“触摸”中的儿童收藏
//ItemContainerGenerator正确初始化的顺序。
var NecessaryChildrenTouch=儿童;
IIItemContainerGenerator生成器=ItemContainerGenerator;
IDisposable generationAction=null;
int指数=0;
Rect visibilityRect=新Rect(
-水平偏移/缩放因子,
-垂直偏移/缩放因子,
实际宽度/缩放因子,
实际高度/缩放因子);
//循环浏览项目列表并生成其容器
//如果它们包含在当前可见视图中。
foreach(itemsOwner.Items中的对象项)
{
var virtualizedItem=作为IVirtualizationCanvasItem的项目;
如果(virtualizedItem==null | |
visibilityRect.IntersectsWith(GetBounds(virtualizedItem)))
{
if(generationAction==null)
{
发电机位置起始位置=
generator.GeneratorPositionFromIndex(索引);
generationAction=generator.StartAt(startPosition,
生成方向。向前,正确);
}
生成项(索引);
}
其他的
{
GeneratorPosition itemPosition=
generator.GeneratorPositionFromIndex(索引);
if(itemPosition.Index!=-1&&itemPosition.Offset==0)
{
RemoveInternalChildRange(索引,1);
发电机。拆除(项目位置,1);
}
//当我们跳过某些项目时,需要“重置”生成器
//在序列中。。。
if(generationAction!=null)
{
generationAction.Dispose();
generationAction=null;
}
}
++指数;
}
if(generationAction!=null)
{
generationAction.Dispose();
}
返回默认值(大小);
}
(...)
私有void GenerateItem(整数索引)
{
布尔新词化;
变量元素=
ItemContainerGenerator.GenerateNext(out newlyRealized)作为UIElement;
如果(新实现)
{
如果(索引>=InternalChildren.Count)
{
AddInternalChild(元素);
}
其他的
{
InsertInternalChild(索引、元素);
}
ItemContainerGenerator.PrepareItemContainer(元素);
element.RenderTransform=\u scaleTransform;
}
元素。测量(新尺寸(双正不确定度,
双重(正不确定性);
}
每当从可视化树中删除容器时,都会使用它,原因可能是删除了相应的项,或刷新了集合,或将容器从屏幕上滚动并重新虚拟化
这是WPF4中的一个已知错误
请看,它还提供了一个您可以应用的变通方法
“通过保存引用,您可以使您的解决方案更加健壮
第一次看到sentinel对象{DisconnectedItem}时,
然后与之后保存的值进行比较
我们应该公开测试{DisconnectedItem},但是
它从裂缝中滑了出来。我们将在将来的版本中修复它,但是
现在你可以相信一个事实,那就是
{DisconnectedItem}对象。“
我已经晚了6年,但问题仍然没有在WPF中得到解决。这是解决方案(变通方法) 对DataContext进行自绑定,例如:
<Image DataContext="{Binding}" />
这对我来说很有效,即使是对于一个非常复杂的xaml。你是在回收容器吗?@Blam:我不认为我是,你说回收容器是什么意思?只要搜索msdn中的回收容器就可以了,只是一个触手可及的地方,也只是一个很好的例子comment@Blam:谢谢,我试过使用虚拟化StackPanel并打开容器回收。不幸的是,我仍然我遇到了同样的问题,即:当项目被虚拟化时,会生成DisconnectedItems。“Microsoft Connect已在stackoverflow中退役”。干得好,Microsoft(你真漂亮!修复了我与项目相关的问题)