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(0, 0), child.RenderSize));
            var ownerRectangle = new Rect(new Point(0, 0), parent.RenderSize);
            return ownerRectangle.IntersectsWith(childRectangle);
        }

        public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
        {
            if (obj != null)
            {
                for (int i = 0; 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 = 0; 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呢?

时间: 2024-10-26 21:26:07

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

WPF的UI虚拟化

许多时候,我们的界面上会呈现大量的数据,如包含数千条记录的表格或包含数百张照片的相册.由于呈现UI是一件开销比较大的动作,一次性呈现数百张照片就目前的电脑性能来说是需要占用大量内存和时间的.因此需要对其进行优化.以前采用的方案大多数是翻页,翻页在某种程度上造成用户浏览的中断,因此现在往往采用一种新的方案——UI虚拟化. UI虚拟化的原理是:但是由于显示器和人眼的限制,用户往往只会同时看到其中的数十条数据,因此只要在界面上渲染用户所看到的那些数据即可,对于用户呈现的界面仍然是一样的.微软的MSDN

WPF之UI虚拟化

原文:WPF之UI虚拟化 在WPF应用程序开发过程中,大数据量的数据展现通常都要考虑性能问题.有下面一种常见的情况:原始数据源数据量很大,但是某一时刻数据容器中的可见元素个数是有限的,剩余大多数元素都处于不可见状态,如果一次性将所有的数据元素都渲染出来则会非常的消耗性能.因而可以考虑只渲染当前可视区域内的元素,当可视区域内的元素需要发生改变时,再渲染即将展现的元素,最后将不再需要展现的元素清除掉,这样可以大大提高性能. 对于ListBox,在XAML Template中加入以下属性 Scroll

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

WPF 显示文件列表中使用 ListBox 变到ListView 最后使用DataGrid 故事背景: 需要检索某目录下文件,并列出来,提供选择和其他功能. 第一版需求: 列出文件供选择即可,代码如下: <ListBox Name="multiSelectFileLst" ItemsSource="{Binding FileList}" Grid.Row="1" Grid.Column="1" > <List

查看CPU是否支持虚拟化

参考:http://www.cnblogs.com/jankie/archive/2012/07/04/2575695.html 一.Windows平台:使用cpu-Z即可查看. 二.Linux平台:在终端执行#cat /proc/cpuinfo(或#grep -E '(vmx|svm)' /proc/cpuinfo)命令,找到flags部分,如果其中输出有VMX或SVM,即表明支持虚拟化技术. 三. Linux显示的flags部分解释:fpu – Onboard FPUvme – Virtua

VMware中让虚拟机支持虚拟化

一.问题 由于需要玩一下OpenNebula,但是现在自己只有一台笔记本,如何玩?当然是VMVare了,于是装了几台Ubuntu的虚拟机,但是在看安装OpenNebula的前提要求是 安装的主机cpu必须支持虚拟化,于是我用了命令查看cpu是否支持虚拟化 cat /proc/cpuinfo | grep vmx如下图,什么也没有返回 没返回则说明cpu不支持虚拟化,就是在虚拟机中不能安装OpenNebula了,怎么办呢 二.解决问题 关闭虚拟机,打开虚拟机设置,如下图所示,点击cpu的位置,在右

怎么看主机是否支持虚拟化

securable下载这个工具: 第一项是检测处理器是否支持64位拓展技术:第二项是检测处理器是否支持硬件数据执行保护(DEP),能够在内存上执行额外检查以帮助防止在系统上运行恶意代码:第三项是检测是否支持虚拟化. 虚拟化的几种状态的含义-No--CPU不支持虚拟化YES--CPU支持虚拟化Locked on--CPU支持虚拟化,但虚拟化的开启由BIOS控制,现在已开启Locked off--CPU支持虚拟化,但虚拟化的开启由BIOS控制,现在未开启其实显示Locked on/off和YES还有

如何知道 CPU 是否支持虚拟化技术(VT)

作者: Sk 译者: LCTT geekpi 我们已经知道如何检查你的 Linux 操作系统是 32 位还是 64 位以及如何知道你的 Linux 系统是物理机还是虚拟机.今天,我们将学习另一个有用的话题 - 如何知道 CPU 是否支持虚拟化技术 (VT)?在安装虚拟化程序(如 VirtualBox 或 VMWare workstation)以在 Linux 系统上运行虚拟机之前,你应该首先验证这一点.现在让我们来看看你的电脑是否支持 VT.相信我,这真的很简单! 了解 CPU 是否支持虚拟化技

如何查看当前linux服务器是否支持虚拟化

[[email protected] ~]# grep -E '(svm|vmx)' /proc/cpuinfo 或者: [[email protected] ~]# cat /proc/cpuinfo 找到flags部分,如果其中输出有SVM或VMX,表明CPU支持虚拟化技术: ==> svm - Secure virtual machine, AMD的虚拟化技术AMD-V ==> vmx - Intel的虚拟化技术Intel-VT kvm虚拟化的嵌套: [email protected]:

WPF 列表开启虚拟化的方式

正确开启虚拟化的方式 列表如ListBox,ListView,TreeView,GridView等,开启虚拟化 ScrollViewer设置CanContentScroll=True 直接在模板中,设置CanContentScroll="True" 如模板中未设置CanContentScroll属性,可以在列表添加属性ScrollViewer.CanContentScroll="True". 注意:如果在模板中设置CanContentScroll="Fal