WPF:间接支持虚拟化的ListBox
/// <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的更多相关文章
- WPF的UI虚拟化
许多时候,我们的界面上会呈现大量的数据,如包含数千条记录的表格或包含数百张照片的相册.由于呈现UI是一件开销比较大的动作,一次性呈现数百张照片就目前的电脑性能来说是需要占用大量内存和时间的.因此需要对 ...
- 【WPF】UI虚拟化之------自定义VirtualizingWrapPanel
原文:[WPF]UI虚拟化之------自定义VirtualizingWrapPanel 前言 前几天QA报了一个关于OOM的bug,在排查的过程中发现,ListBox控件中被塞入了过多的Item,而 ...
- WPF 显示文件列表中使用 ListBox 变到ListView 最后使用DataGrid
WPF 显示文件列表中使用 ListBox 变到ListView 最后使用DataGrid 故事背景: 需要检索某目录下文件,并列出来,提供选择和其他功能. 第一版需求: 列出文件供选择即可,代码如下 ...
- 查看CPU是否支持虚拟化
参考:http://www.cnblogs.com/jankie/archive/2012/07/04/2575695.html 一.Windows平台:使用cpu-Z即可查看. 二.Linux平台: ...
- 问题 Windows7VMware14安装虚拟机时出现 此主机不支持虚拟化实际模式。需要具备 Intel“VMX 不受限客户机”功能才能在 Intel 处理器上运行此虚拟机。 模块“CPUIDEarly”启动失败。
问题 Windows7VMware14安装虚拟机时出现 此主机不支持虚拟化实际模式.需要具备 Intel“VMX 不受限客户机”功能才能在 Intel 处理器上运行此虚拟机. 模块“CPUIDEarl ...
- CentOS 7下KVM支持虚拟化/嵌套虚拟化配置
开启虚拟化: cat << EOF > /etc/modprobe.d/kvm-nested.conf options kvm-intel nested=1 options kvm- ...
- VMware中让虚拟机支持虚拟化
一.问题 由于需要玩一下OpenNebula,但是现在自己只有一台笔记本,如何玩?当然是VMVare了,于是装了几台Ubuntu的虚拟机,但是在看安装OpenNebula的前提要求是 安装的主机cpu ...
- 怎样知道 CPU 是否支持虚拟化技术(VT) | Linux 中国
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/F8qG7f9YD02Pe/article/details/79832475 wx_fmt=png&a ...
- 英特尔老款CPU支持虚拟化对照表(转)
说明:一般来说新款的挤牙膏公司出的CPU都基本支持虚拟化,但不包括Atom系列的,也就是小主机低功耗机器使用的CPU. Intel® Virtualization Technology List YE ...
随机推荐
- flex弹性布局心得
概述 最近做项目用flex重构了一下网页中的布局,顺便学习了一下flex弹性布局,感觉超级强大,有一些心得,记录下来供以后开发时参考,相信对其他人也有用. 参考资料: Solved by Flexbo ...
- [Swift]LeetCode1 .两数之和 | Two Sum
Given an array of integers, return indices of the two numbers such that they add up to a specific ta ...
- [Swift]LeetCode391. 完美矩形 | Perfect Rectangle
Given N axis-aligned rectangles where N > 0, determine if they all together form an exact cover o ...
- 将dylib库嵌入macOS应用的方法
写作是一种习惯,稍微松懈,也许失去的就很多.过了一个年,居然很多天都没有更新,幸福的代价吧:) 标题的问题其实以前碰到过,不过当时在iOS,所以随手处理了没有重视. 而这次是在macOS,所使用的库, ...
- Java基础11:Java泛型详解
本文对java的泛型的概念和使用做了详尽的介绍. 本文参考https://blog.csdn.net/s10461/article/details/53941091 具体代码在我的GitHub中可以找 ...
- shell高级特性-4
1.shell模块 shell脚本中可以加载配置文件或调用已经完成函数或脚本. a.加载配置文件 新建配置文件config,插入以下代码: reboot_mode=True 在同一路径下,新建文件mo ...
- JDBC 连接池的两种方式——dbcp & c3p0
申明:本文对于连接资源关闭采用自定义的 JDBCUtils 工具: package com.test.utils; import java.sql.Connection; import java.sq ...
- 【c#】RabbitMQ学习文档(六)RPC(远程调用)
远程过程调用(Remote Proceddure call[RPC]) (本实例都是使用的Net的客户端,使用C#编写) 在第二个教程中,我们学习了如何使用工作队列在多个工作实例之间分配耗时的任务. ...
- 补习系列(9)-springboot 定时器,你用对了吗
目录 简介 一.应用启动任务 二.JDK 自带调度线程池 三.@Scheduled 定制 @Scheduled 线程池 四.@Async 定制 @Async 线程池 小结 简介 大多数的应用程序都离不 ...
- NET快速信息化系统开发框架 V3.2 -> “用户管理”主界面使用多表头展示、增加打印功能
RDIFrameowrk.NET 用户管理是使用非常频繁的模块,由于需要展示的字段比较多,以前的展示方式显得不是太规范,现3.2版本用户管理主界面进行了全新的设计,数据列表展示使用了Dev家族全新的G ...