WPF 项目容器回收

发布于 2024-08-26 06:48:19 字数 1530 浏览 4 评论 0原文

我想实现一个自定义 Canvas,当用作 ItemsPanel 时,它会回收容器。因此,我从VirtualizingPanel派生并覆盖ArrangeOverrideMeasureOverride。我正在 MeasureOverride 中进行生成,如下所示:

var children = base.InternalChildren;

var itemsControl = ItemsControl.GetItemsOwner(this);
var itemsCount = itemsControl.Items.Count;

IItemContainerGenerator generator = itemsControl.ItemContainerGenerator;

var startPos = generator.GeneratorPositionFromIndex(0);

using (generator.StartAt(startPos, GeneratorDirection.Forward, true))
{
    for (int i = 0; i < itemsCount; i++)
    {
        bool isNewlyRealized;

        var child = generator.GenerateNext(out isNewlyRealized) as UIElement;

        if (isNewlyRealized)
        {
            base.AddInternalChild(child);
            generator.PrepareItemContainer(child);
        }

        child.Measure(constraint);
    }
}

我不知道如何进行回收。我尝试了类似以下的方法:

protected override void OnItemsChanged(object sender, ItemsChangedEventArgs e)
{
    switch (e.Action)
    {
        case NotifyCollectionChangedAction.Remove:
        case NotifyCollectionChangedAction.Replace:
        case NotifyCollectionChangedAction.Move:
            IRecyclingItemContainerGenerator generator = ItemsControl.GetItemsOwner(this).ItemContainerGenerator;
            generator.Recycle(e.Position, e.ItemUICount);
            RemoveInternalChildRange(e.Position.Index, e.ItemUICount);
            break;
    }
}

但它不起作用。知道如何做到这一点吗?

I want to implement a custom Canvas that recycles containers when used as an ItemsPanel. So I derived from VirtualizingPanel and override the ArrangeOverride and MeasureOverride. I am doing the generation in MeasureOverride like this:

var children = base.InternalChildren;

var itemsControl = ItemsControl.GetItemsOwner(this);
var itemsCount = itemsControl.Items.Count;

IItemContainerGenerator generator = itemsControl.ItemContainerGenerator;

var startPos = generator.GeneratorPositionFromIndex(0);

using (generator.StartAt(startPos, GeneratorDirection.Forward, true))
{
    for (int i = 0; i < itemsCount; i++)
    {
        bool isNewlyRealized;

        var child = generator.GenerateNext(out isNewlyRealized) as UIElement;

        if (isNewlyRealized)
        {
            base.AddInternalChild(child);
            generator.PrepareItemContainer(child);
        }

        child.Measure(constraint);
    }
}

What I don't know is how to make the recycling. I tried something like the following:

protected override void OnItemsChanged(object sender, ItemsChangedEventArgs e)
{
    switch (e.Action)
    {
        case NotifyCollectionChangedAction.Remove:
        case NotifyCollectionChangedAction.Replace:
        case NotifyCollectionChangedAction.Move:
            IRecyclingItemContainerGenerator generator = ItemsControl.GetItemsOwner(this).ItemContainerGenerator;
            generator.Recycle(e.Position, e.ItemUICount);
            RemoveInternalChildRange(e.Position.Index, e.ItemUICount);
            break;
    }
}

But it doesn't work. Any idea how to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

貪欢 2024-09-02 06:48:19

看这里:
http://blogs.claritycon.com/blogs/lee_roth/default.aspx

我通过以下方式进行回收:

OnItemsChanged 中,我仅调用 RemoveInternalChildRange

protected override void OnItemsChanged(object sender, ItemsChangedEventArgs args)
    {
      switch (args.Action)
      {
        case NotifyCollectionChangedAction.Remove:
        case NotifyCollectionChangedAction.Replace:
          RemoveInternalChildRange(args.Position.Index, args.ItemUICount);
          break;
        case NotifyCollectionChangedAction.Move:
          RemoveInternalChildRange(args.OldPosition.Index, args.ItemUICount);
          break;
      }
    }

在 Measure override 中,我首先添加新项目,然后删除旧项目。
如果你使用回收,你必须知道,如果你得到一个回收的容器,你通过调用GenerateNext得到的新标志也是假的。

这里我们添加新的项目:

GeneratorPosition start = ItemContainerGenerator.GeneratorPositionFromIndex(iFirstItemIndex);
      int iChildIndex = (start.Offset == 0) ? start.Index : start.Index + 1;
      using (ItemContainerGenerator.StartAt(start, GeneratorDirection.Forward, true))
      {
        for (int i = iFirstItemIndex; i <= iLastItemIndex; i++, iChildIndex++)
        {
          bool bNew;
          UIElement element = (UIElement)ItemContainerGenerator.GenerateNext(out bNew);
          //If we get a new instance
          if (bNew)
          {
            if (iChildIndex >= Children.Count) AddInternalChild(element);
            else InsertInternalChild(iChildIndex, element);
            ItemContainerGenerator.PrepareItemContainer(element);
          }
          //If we get a recycled element
          else if (!InternalChildren.Contains(element))
          {
            InsertInternalChild(iChildIndex, element);
            ItemContainerGenerator.PrepareItemContainer(element);
          }
          element.Measure(...);
        }
      }

添加项目后,我们删除旧的项目:

for (int i = Children.Count - 1; i >= 0; i--)
      {
        GeneratorPosition childGeneratorPosition = new GeneratorPosition(i, 0);
        int iIndex = ItemContainerGenerator.IndexFromGeneratorPosition(childGeneratorPosition);
        if (iIndex < iFirstItemIndex || iIndex > iLastItemIndex)
        {
          //remove() calls ItemContainerGenerator.remove() OR recycle(). Both works.
          remove(childGeneratorPosition, 1);
          RemoveInternalChildRange(i, 1);
        }
      }

希望可以帮到你。

Look here:
http://blogs.claritycon.com/blogs/lee_roth/default.aspx

I make recycling the following way:

In OnItemsChanged, I only call RemoveInternalChildRange:

protected override void OnItemsChanged(object sender, ItemsChangedEventArgs args)
    {
      switch (args.Action)
      {
        case NotifyCollectionChangedAction.Remove:
        case NotifyCollectionChangedAction.Replace:
          RemoveInternalChildRange(args.Position.Index, args.ItemUICount);
          break;
        case NotifyCollectionChangedAction.Move:
          RemoveInternalChildRange(args.OldPosition.Index, args.ItemUICount);
          break;
      }
    }

In Measure override, I first add new items, then I remove the old ones.
If you use recycling you have to know that the new-Flag that you get by calling GenerateNext is also false if you get a recycled container.

Here we add new Items:

GeneratorPosition start = ItemContainerGenerator.GeneratorPositionFromIndex(iFirstItemIndex);
      int iChildIndex = (start.Offset == 0) ? start.Index : start.Index + 1;
      using (ItemContainerGenerator.StartAt(start, GeneratorDirection.Forward, true))
      {
        for (int i = iFirstItemIndex; i <= iLastItemIndex; i++, iChildIndex++)
        {
          bool bNew;
          UIElement element = (UIElement)ItemContainerGenerator.GenerateNext(out bNew);
          //If we get a new instance
          if (bNew)
          {
            if (iChildIndex >= Children.Count) AddInternalChild(element);
            else InsertInternalChild(iChildIndex, element);
            ItemContainerGenerator.PrepareItemContainer(element);
          }
          //If we get a recycled element
          else if (!InternalChildren.Contains(element))
          {
            InsertInternalChild(iChildIndex, element);
            ItemContainerGenerator.PrepareItemContainer(element);
          }
          element.Measure(...);
        }
      }

After adding Items we remove the old Items:

for (int i = Children.Count - 1; i >= 0; i--)
      {
        GeneratorPosition childGeneratorPosition = new GeneratorPosition(i, 0);
        int iIndex = ItemContainerGenerator.IndexFromGeneratorPosition(childGeneratorPosition);
        if (iIndex < iFirstItemIndex || iIndex > iLastItemIndex)
        {
          //remove() calls ItemContainerGenerator.remove() OR recycle(). Both works.
          remove(childGeneratorPosition, 1);
          RemoveInternalChildRange(i, 1);
        }
      }

I hope I could help you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文