/// <summary>
/// 间接实现了虚拟化的ListBox
/// 子项必须实现IVisible接口
/// 你可以在IsVisible发生改变时实现一系列自定义动作
/// 比如:当IsVisible = false时,清空子项的内容;当IsVisible = true时,还原子项的内容
/// </summary>
public class VirtualizedListBox : ListBox
{
private ScrollViewer scrollViewer; public override void OnApplyTemplate()
{
scrollViewer = FindVisualChild<ScrollViewer>(this);
if (scrollViewer != null)
{
scrollViewer.ScrollChanged -= OnScrollChanged;
scrollViewer.ScrollChanged += OnScrollChanged;
}
} #region 事件
/// <summary>
/// 滚动条滚动事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnScrollChanged(object sender, ScrollChangedEventArgs e)
{
foreach (IVisible item in this.Items)
{
var listBoxItem = (FrameworkElement)this.ItemContainerGenerator.ContainerFromItem(item);
item.IsVisible = IsChildVisibleInParent(listBoxItem, scrollViewer);
}
}
#endregion #region 私有方法
/// <summary>
/// 判断子控件是否在父控件中可见
/// </summary>
/// <param name="child">子控件</param>
/// <param name="parent">父控件</param>
/// <returns></returns>
private bool IsChildVisibleInParent(FrameworkElement child, FrameworkElement parent)
{
var childTransform = child.TransformToAncestor(parent);
var childRectangle = childTransform.TransformBounds(new Rect(new Point(, ), child.RenderSize));
var ownerRectangle = new Rect(new Point(, ), parent.RenderSize);
return ownerRectangle.IntersectsWith(childRectangle);
} public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
if (obj != null)
{
for (int i = ; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is T)
{
return (T)child;
}
T childItem = FindVisualChild<T>(child);
if (childItem != null) return childItem;
}
}
return null;
}
#endregion
}

VirtualizedListBox

    /// <summary>
/// 表示可见的类型
/// </summary>
public interface IVisible
{
/// <summary>
/// 是否可见
/// </summary>
bool IsVisible
{
get;
set;
}
}

IVisible

核心代码是IsChildVisibleInParent方法,可以判断某个子控件是否在父控件中可见。

针对ListBox,需要判断某个ListBoxItem是否在ListBox的ScrollView中可见。然后根据子项是否可见,再对子项进行处理,实现间接的虚拟化。

于是,需要获取ListBox的模板中的ScrollViewer。于是,祭出神器:

public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
if (obj != null)
{
for (int i = ; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is T)
{
return (T)child;
}
T childItem = FindVisualChild<T>(child);
if (childItem != null) return childItem;
}
}
return null;
}

FindVisualChild

这个方法,我觉得了解WPF的应该都知道。我甚至在学习WPF的第一天就见到了这个方法。

一开始,我在VirtualizedListBox的构造函数中调用此方法,发现获取到的ScrollViewer是空的。

我想,应该这时候ListBox还没开始加载。

然后,我在ListBox的Loaded事件中调用此方法,发现获取到的ScrollViewer还是空的。

什么鬼?感觉有点颠覆三观。

最后,我心灰意冷,把键盘砸了。砸键盘的过程中,代码成了。

嘿嘿,不知道大家是否知道在什么情况下,ListBox即使已经加载完成(Loaded),却依然无法获取到ListBox控件模板中的ScrollViewer呢?

WPF:间接支持虚拟化的ListBox的更多相关文章

  1. WPF的UI虚拟化

    许多时候,我们的界面上会呈现大量的数据,如包含数千条记录的表格或包含数百张照片的相册.由于呈现UI是一件开销比较大的动作,一次性呈现数百张照片就目前的电脑性能来说是需要占用大量内存和时间的.因此需要对 ...

  2. 【WPF】UI虚拟化之------自定义VirtualizingWrapPanel

    原文:[WPF]UI虚拟化之------自定义VirtualizingWrapPanel 前言 前几天QA报了一个关于OOM的bug,在排查的过程中发现,ListBox控件中被塞入了过多的Item,而 ...

  3. WPF 显示文件列表中使用 ListBox 变到ListView 最后使用DataGrid

    WPF 显示文件列表中使用 ListBox 变到ListView 最后使用DataGrid 故事背景: 需要检索某目录下文件,并列出来,提供选择和其他功能. 第一版需求: 列出文件供选择即可,代码如下 ...

  4. 查看CPU是否支持虚拟化

    参考:http://www.cnblogs.com/jankie/archive/2012/07/04/2575695.html 一.Windows平台:使用cpu-Z即可查看. 二.Linux平台: ...

  5. 问题 Windows7VMware14安装虚拟机时出现 此主机不支持虚拟化实际模式。需要具备 Intel“VMX 不受限客户机”功能才能在 Intel 处理器上运行此虚拟机。 模块“CPUIDEarly”启动失败。

    问题 Windows7VMware14安装虚拟机时出现 此主机不支持虚拟化实际模式.需要具备 Intel“VMX 不受限客户机”功能才能在 Intel 处理器上运行此虚拟机. 模块“CPUIDEarl ...

  6. CentOS 7下KVM支持虚拟化/嵌套虚拟化配置

    开启虚拟化: cat << EOF > /etc/modprobe.d/kvm-nested.conf options kvm-intel nested=1 options kvm- ...

  7. VMware中让虚拟机支持虚拟化

    一.问题 由于需要玩一下OpenNebula,但是现在自己只有一台笔记本,如何玩?当然是VMVare了,于是装了几台Ubuntu的虚拟机,但是在看安装OpenNebula的前提要求是 安装的主机cpu ...

  8. 怎样知道 CPU 是否支持虚拟化技术(VT) | Linux 中国

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/F8qG7f9YD02Pe/article/details/79832475 wx_fmt=png&a ...

  9. 英特尔老款CPU支持虚拟化对照表(转)

    说明:一般来说新款的挤牙膏公司出的CPU都基本支持虚拟化,但不包括Atom系列的,也就是小主机低功耗机器使用的CPU. Intel® Virtualization Technology List YE ...

随机推荐

  1. freekan5.9电影网站安装及源码分享

    Freekan是一套目前非常火的电影网站系统,全自动采集,支持对接公众号 服务器环境:centos7,宝塔面板,php7.1(重要),nignx,mysql 1.首先上传压缩包到网站目录,然后解压 2 ...

  2. [Swift]LeetCode729. 我的日程安排表 I | My Calendar I

    Implement a MyCalendar class to store your events. A new event can be added if adding the event will ...

  3. [Swift]LeetCode997. 找到小镇的法官 | Find the Town Judge

    In a town, there are N people labelled from 1 to N.  There is a rumor that one of these people is se ...

  4. python-类的定制

    1.看到类似__slots__这种形如__xxx__的变量或者函数名就要注意,这些在Python中是有特殊用途的.__slots__我们已经知道怎么用了,__len__()方法我们也知道是为了能让cl ...

  5. 原有vue项目接入typescript

    原有vue项目接入typescript 为什么要接入typescript javascript由于自身的弱类型,使用起来非常灵活. 这也就为大型项目.多人协作开发埋下了很多隐患.如果是自己的私有业务倒 ...

  6. mongo 删除 表中字段

    查询语句 db.getCollection("A表").update( { } ,{   $unset:{"a":1}  } , {multi: true} ) ...

  7. Xapian的内存索引-添加文档

    本文主要记录Xapian的内存索引在添加文档过程中,做了哪些事情. 内容主要为函数执行过程中的流水线. demo代码: Xapian::WritableDatabase db = Xapian::In ...

  8. [Abp 源码分析]四、模块配置

    0.简要介绍 在 Abp 框架当中通过各种 Configuration 来实现模块的配置,Abp 本身提供的很多基础设施功能的一些在运行时的行为是通过很多不同的 Configuration 来开放给用 ...

  9. 利用NPOI生成word文档(c#)

    WordTest.aspx.cs using System; using System.IO; using System.Text; using System.Web; using System.We ...

  10. Chapter 5 Blood Type——7

    "You say that a lot," I noted, trying to ignore the sudden trembling in my stomach and kee ...