备份一个 VirtualizingWrapPanel ,支持虚拟化
1 using System;
2 using System.Collections.Generic;
3 using System.Diagnostics;
4 using System.Linq;
5 using System.Text;
6 using System.Threading.Tasks;
7 using System.Windows;
8 using System.Windows.Controls;
9 using System.Windows.Controls.Primitives;
10 using System.Windows.Media;
11
12 namespace Cal.Wpf.Controls
13 {
14 /// <summary>
15 /// 方块模式的布局,支持虚拟化
16 /// ScrollOffset 每次滚动的距离
17 /// <local:VirtualizingWrapPanel ScrollOffset="50" ChildHeight="200" ChildWidth="200"/>
18 /// </summary>
19 public class VirtualizingWrapPanel : VirtualizingPanel, IScrollInfo
20 {
21 #region 变量
22 private TranslateTransform trans = new TranslateTransform();
23 #endregion
24
25 #region 构造函数
26 public VirtualizingWrapPanel()
27 {
28 this.RenderTransform = trans;
29 }
30 #endregion
31
32 #region 附加属性
33 public static readonly DependencyProperty ChildWidthProperty = DependencyProperty.RegisterAttached("ChildWidth", typeof(double), typeof(VirtualizingWrapPanel), new FrameworkPropertyMetadata(200.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
34
35 public static readonly DependencyProperty ChildHeightProperty = DependencyProperty.RegisterAttached("ChildHeight", typeof(double), typeof(VirtualizingWrapPanel), new FrameworkPropertyMetadata(200.0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
36
37 public static readonly DependencyProperty ScrollOffsetProperty = DependencyProperty.RegisterAttached("ScrollOffset", typeof(int), typeof(VirtualizingWrapPanel), new PropertyMetadata(10));
38
39 /// <summary>
40 /// 鼠标每一次滚动 UI上的偏移
41 /// </summary>
42 public int ScrollOffset
43 {
44 get { return Convert.ToInt32(GetValue(ScrollOffsetProperty)); }
45 set { SetValue(ScrollOffsetProperty, value); }
46 }
47
48 /// <summary>
49 /// 元素宽度
50 /// </summary>
51 public double ChildWidth
52 {
53 get => Convert.ToDouble(GetValue(ChildWidthProperty));
54 set => SetValue(ChildWidthProperty, value);
55 }
56
57 /// <summary>
58 /// 元素高度
59 /// </summary>
60 public double ChildHeight
61 {
62 get => Convert.ToDouble(GetValue(ChildHeightProperty));
63 set => SetValue(ChildHeightProperty, value);
64 }
65 #endregion
66
67 #region 私有方法
68
69
70 int GetItemCount(DependencyObject element)
71 {
72 var itemsControl = ItemsControl.GetItemsOwner(element);
73 return itemsControl.HasItems ? itemsControl.Items.Count : 0;
74 }
75
76 int CalculateChildrenPerRow(Size availableSize)
77 {
78 int childPerRow = 0;
79 if (availableSize.Width == double.PositiveInfinity)
80 childPerRow = this.Children.Count;
81 else
82 childPerRow = Math.Max(1, Convert.ToInt32(Math.Floor(availableSize.Width / this.ChildWidth)));
83 return childPerRow;
84 }
85
86 /// <summary>
87 /// width不超过availableSize的情况下,自身实际需要的Size(高度可能会超出availableSize)
88 /// </summary>
89 /// <param name="availableSize"></param>
90 /// <param name="itemsCount"></param>
91 /// <returns></returns>
92 Size CalculateExtent(Size availableSize, int itemsCount)
93 {
94 int childPerRow = CalculateChildrenPerRow(availableSize);//现有宽度下 一行可以最多容纳多少个
95 return new Size(childPerRow * this.ChildWidth, this.ChildHeight * Math.Ceiling(Convert.ToDouble(itemsCount) / childPerRow));
96 }
97
98 /// <summary>
99 /// 更新滚动条
100 /// </summary>
101 /// <param name="availableSize"></param>
102 void UpdateScrollInfo(Size availableSize)
103 {
104 var extent = CalculateExtent(availableSize, GetItemCount(this));//extent 自己实际需要
105 if (extent != this.extent)
106 {
107 this.extent = extent;
108 this.ScrollOwner.InvalidateScrollInfo();
109 }
110 if (availableSize != this.viewPort)
111 {
112 this.viewPort = availableSize;
113 this.ScrollOwner.InvalidateScrollInfo();
114 }
115 }
116
117 /// <summary>
118 /// 获取所有item,在可视区域内第一个item和最后一个item的索引
119 /// </summary>
120 /// <param name="firstIndex"></param>
121 /// <param name="lastIndex"></param>
122 void GetVisiableRange(ref int firstIndex, ref int lastIndex)
123 {
124 int childPerRow = CalculateChildrenPerRow(this.extent);
125 firstIndex = Convert.ToInt32(Math.Floor(this.offset.Y / this.ChildHeight)) * childPerRow;
126 lastIndex = Convert.ToInt32(Math.Ceiling((this.offset.Y + this.viewPort.Height) / this.ChildHeight)) * childPerRow - 1;
127 int itemsCount = GetItemCount(this);
128 if (lastIndex >= itemsCount)
129 lastIndex = itemsCount - 1;
130
131 }
132
133 /// <summary>
134 /// 将不在可视区域内的item 移除
135 /// </summary>
136 /// <param name="startIndex">可视区域开始索引</param>
137 /// <param name="endIndex">可视区域结束索引</param>
138 void CleanUpItems(int startIndex, int endIndex)
139 {
140 var children = this.InternalChildren;
141 var generator = this.ItemContainerGenerator;
142 for (int i = children.Count - 1; i >= 0; i--)
143 {
144 var childGeneratorPosi = new GeneratorPosition(i, 0);
145 int itemIndex = generator.IndexFromGeneratorPosition(childGeneratorPosi);
146
147 if (itemIndex < startIndex || itemIndex > endIndex)
148 {
149
150 generator.Remove(childGeneratorPosi, 1);
151 RemoveInternalChildRange(i, 1);
152 }
153 }
154 }
155
156 /// <summary>
157 /// scroll/availableSize/添加删除元素 改变都会触发 edit元素不会改变
158 /// </summary>
159 /// <param name="availableSize"></param>
160 /// <returns></returns>
161 protected override Size MeasureOverride(Size availableSize)
162 {
163 this.UpdateScrollInfo(availableSize);//availableSize更新后,更新滚动条
164 int firstVisiableIndex = 0, lastVisiableIndex = 0;
165 GetVisiableRange(ref firstVisiableIndex, ref lastVisiableIndex);//availableSize更新后,获取当前viewport内可放置的item的开始和结束索引 firstIdnex-lastIndex之间的item可能部分在viewport中也可能都不在viewport中。
166
167 UIElementCollection children = this.InternalChildren;//因为配置了虚拟化,所以children的个数一直是viewport区域内的个数,如果没有虚拟化则是ItemSource的整个的个数
168 IItemContainerGenerator generator = this.ItemContainerGenerator;
169 //获得第一个可被显示的item的位置
170 GeneratorPosition startPosi = generator.GeneratorPositionFromIndex(firstVisiableIndex);
171 int childIndex = (startPosi.Offset == 0) ? startPosi.Index : startPosi.Index + 1;//startPosi在chilren中的索引
172 using (generator.StartAt(startPosi, GeneratorDirection.Forward, true))
173 {
174 int itemIndex = firstVisiableIndex;
175 while (itemIndex <= lastVisiableIndex)//生成lastVisiableIndex-firstVisiableIndex个item
176 {
177 bool newlyRealized = false;
178 var child = generator.GenerateNext(out newlyRealized) as UIElement;
179 if (newlyRealized)
180 {
181 if (childIndex >= children.Count)
182 base.AddInternalChild(child);
183 else
184 {
185 base.InsertInternalChild(childIndex, child);
186 }
187 generator.PrepareItemContainer(child);
188 }
189 else
190 {
191 //处理 正在显示的child被移除了这种情况
192 if (!child.Equals(children[childIndex]))
193 {
194 base.RemoveInternalChildRange(childIndex, 1);
195 }
196 }
197 child.Measure(new Size(this.ChildWidth, this.ChildHeight));
198 //child.DesiredSize//child想要的size
199 itemIndex++;
200 childIndex++;
201 }
202 }
203 CleanUpItems(firstVisiableIndex, lastVisiableIndex);
204 return new Size(double.IsInfinity(availableSize.Width) ? 0 : availableSize.Width, double.IsInfinity(availableSize.Height) ? 0 : availableSize.Height);//自身想要的size
205 }
206
207 protected override Size ArrangeOverride(Size finalSize)
208 {
209 Debug.WriteLine("----ArrangeOverride");
210 var generator = this.ItemContainerGenerator;
211 UpdateScrollInfo(finalSize);
212 int childPerRow = CalculateChildrenPerRow(finalSize);
213 double availableItemWidth = finalSize.Width / childPerRow;
214 for (int i = 0; i <= this.Children.Count - 1; i++)
215 {
216 var child = this.Children[i];
217 int itemIndex = generator.IndexFromGeneratorPosition(new GeneratorPosition(i, 0));
218 int row = itemIndex / childPerRow;//current row
219 int column = itemIndex % childPerRow;
220 double xCorrdForItem = 0;
221
222 xCorrdForItem = column * availableItemWidth + (availableItemWidth - this.ChildWidth) / 2;
223
224 Rect rec = new Rect(xCorrdForItem, row * this.ChildHeight, this.ChildWidth, this.ChildHeight);
225 child.Arrange(rec);
226 }
227 return finalSize;
228 }
229
230 protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
231 {
232 base.OnRenderSizeChanged(sizeInfo);
233 this.SetVerticalOffset(this.VerticalOffset);
234 }
235
236 protected override void OnClearChildren()
237 {
238 base.OnClearChildren();
239 this.SetVerticalOffset(0);
240 }
241
242 protected override void BringIndexIntoView(int index)
243 {
244 if (index < 0 || index >= Children.Count)
245 throw new ArgumentOutOfRangeException();
246 int row = index / CalculateChildrenPerRow(RenderSize);
247 SetVerticalOffset(row * this.ChildHeight);
248 }
249
250 #endregion
251
252 #region IScrollInfo Interface
253 public bool CanVerticallyScroll { get; set; }
254 public bool CanHorizontallyScroll { get; set; }
255
256 private Size extent = new Size(0, 0);
257 public double ExtentWidth => this.extent.Width;
258
259 public double ExtentHeight => this.extent.Height;
260
261 private Size viewPort = new Size(0, 0);
262 public double ViewportWidth => this.viewPort.Width;
263
264 public double ViewportHeight => this.viewPort.Height;
265
266 private Point offset;
267 public double HorizontalOffset => this.offset.X;
268
269 public double VerticalOffset => this.offset.Y;
270
271 public ScrollViewer ScrollOwner { get; set; }
272
273 public void LineDown()
274 {
275 this.SetVerticalOffset(this.VerticalOffset + this.ScrollOffset);
276 }
277
278 public void LineLeft()
279 {
280 throw new NotImplementedException();
281 }
282
283 public void LineRight()
284 {
285 throw new NotImplementedException();
286 }
287
288 public void LineUp()
289 {
290 this.SetVerticalOffset(this.VerticalOffset - this.ScrollOffset);
291 }
292
293 public Rect MakeVisible(Visual visual, Rect rectangle)
294 {
295 return new Rect();
296 }
297
298 public void MouseWheelDown()
299 {
300 this.SetVerticalOffset(this.VerticalOffset + this.ScrollOffset);
301 }
302
303 public void MouseWheelLeft()
304 {
305 throw new NotImplementedException();
306 }
307
308 public void MouseWheelRight()
309 {
310 throw new NotImplementedException();
311 }
312
313 public void MouseWheelUp()
314 {
315 this.SetVerticalOffset(this.VerticalOffset - this.ScrollOffset);
316 }
317
318 public void PageDown()
319 {
320 this.SetVerticalOffset(this.VerticalOffset + this.viewPort.Height);
321 }
322
323 public void PageLeft()
324 {
325 throw new NotImplementedException();
326 }
327
328 public void PageRight()
329 {
330 throw new NotImplementedException();
331 }
332
333 public void PageUp()
334 {
335 this.SetVerticalOffset(this.VerticalOffset - this.viewPort.Height);
336 }
337
338 public void SetHorizontalOffset(double offset)
339 {
340 throw new NotImplementedException();
341 }
342
343 public void SetVerticalOffset(double offset)
344 {
345 if (offset < 0 || this.viewPort.Height >= this.extent.Height)
346 offset = 0;
347 else
348 if (offset + this.viewPort.Height >= this.extent.Height)
349 offset = this.extent.Height - this.viewPort.Height;
350
351 this.offset.Y = offset;
352 this.ScrollOwner?.InvalidateScrollInfo();
353 this.trans.Y = -offset;
354 this.InvalidateMeasure();
355 //接下来会触发MeasureOverride()
356 }
357 #endregion
358 }
359 }
备份一个 VirtualizingWrapPanel ,支持虚拟化的更多相关文章
- 怎样知道 CPU 是否支持虚拟化技术(VT) | Linux 中国
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/F8qG7f9YD02Pe/article/details/79832475 wx_fmt=png&a ...
- 如何知道 CPU 是否支持虚拟化技术(VT)
作者: Sk 译者: LCTT geekpi 我们已经知道如何检查你的 Linux 操作系统是 32 位还是 64 位以及如何知道你的 Linux 系统是物理机还是虚拟机.今天,我们将学习另一个有用的 ...
- 记一个同时支持模糊匹配和静态推导的Atom语法补全插件的开发过程: 序
简介 过去的一周,都睡的很晚,终于做出了Atom上的APICloud语法提示与补全插件:apicloud_autocomplete.个中滋味,感觉还是有必要记录下来的.代码基于 GPL-3.0 开源, ...
- 查看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支持虚拟化对照表(转)
说明:一般来说新款的挤牙膏公司出的CPU都基本支持虚拟化,但不包括Atom系列的,也就是小主机低功耗机器使用的CPU. Intel® Virtualization Technology List YE ...
- 在Wmware虚拟机上如何检查是否CPU支持虚拟化 和 加载kvm模块
在vm虚拟机中 修改 虚拟机==>设置==> 处理器==>虚拟化引擎(选第二项:虚拟化Intel VT-x/EPT 或 AMD-V/RVI(V) ) # vmx或svm :表 ...
- shell实现自动备份整个数据库,一个库备份一个文件
自动实现备份整个数据库 实现一个库备份一个文件 实现排除不需要备份的库 实现备份成压缩文件 实现定义保留多少天的备份文件 核心代码 #!/bin/bash #set -x ############## ...
随机推荐
- dart中Set类型详解
01==> Set 它的主要功能是去除重复的数组内容: Set是没有顺序且不能够重复的数组,所以不能够通过索引值去获取内容 var s = new Set(); s.add('苹果'); s.a ...
- Whois 收集
Whois 收集 Whois是什么 Whois(读作"Who is")是一个标准的互联网协议,主要用于查询域名的注册信息,包括域名所有人.注册商.注册时间.过期时间等详细信息.简单 ...
- JUC并发—1.Java集合包底层源码剖析
大纲 1.为什么要对JDK源码剖析 2.ArrayList源码一:基本原理以及优缺点 3.ArrayList源码二:核心方法的原理 4.ArrayList源码三:数组扩容以及元素拷贝 5.Linked ...
- 浅说 c++20 cppcoro (三)
浅说 c++20 cppcoro (三),https://www.cnblogs.com/bbqzsl/p/18679860 接着上一篇浅说 c++20 coroutine (二) ,继续没说完的事. ...
- [THUWC2017] 在美妙的数学王国中畅游 题解(内附求导小技巧)
事实证明物竞笔记是个好东西,可惜没带,不然还能谎称自己会一点求导和微积分. 顺便在这里把比较经典的一些关于求导的东西记录一下: 常用函数求导: \(C'=0,(x^n)'=nx^{n-1},(\log ...
- window本地部署deepseek
window本地部署deepseek 学习自[[教程]DeepSeek本地免费部署教程,丝滑不卡顿!带你解锁隐藏功能!]https://www.bilibili.com/video/BV1viFaeB ...
- docker下安装Harbor
安装docker-compose # 安装docker-compose curl -L https://github.com/docker/compose/releases/download/1.18 ...
- 【自编RSG插件】梁结构生成插件QGToolBox
正在学习基于ABAQUS-PYTHON的GUI开发,出于练手的想法,编写了一个简单的插件. 实现功能: 基于nodes. rods的table,完成桁架结构的几何建模. GUI界面: RSG Buil ...
- 强!10.8K star!推荐一款用于威胁预防、安全检测的开源监控平台,功能非常强大!!
在当今数字化时代,网络安全威胁日益严峻,企业和组织对于高效.强大的安全解决方案的需求也愈发迫切. 今天给大家分享一个专注于安全监控的开源项目:Wazuh,正是应对这一挑战的有力武器,专门用于帮助个人和 ...
- 记线上+线下培训思想i技巧感悟
刚刚结束一场线下+线上培训 梳理一下,有几个问题: 1.虽然课件自己过了几遍,同时备注里写了一些提示 ,但是真正讲课的时候基本是没有过程特意去扫备注 注意备注应清晰,写核心关键字 2.分屏过程 需要在 ...