备份一个 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 ############## ...
随机推荐
- 移动端如何自动适配px
<script type="text/javascript"> (function(doc, win) { var docEl = doc.documentElemen ...
- 又来新活了!AI电商搜索,或是下一个90亿美元独角兽?
图源:https://www.shopencore.ai/ 全新体验,大模型驱动的对话式购物搜索. Encore, 由2024年10月成立的美国初创公司开发.定位于二手商品对话式购物搜索,最终目标为个 ...
- Linux systemd服务
Linux systemd服务 systemctl命令 systemctl是systemd的主命令,用于管理系统和服务.以下是一些常用的systemctl命令: 查看服务状态:systemctl st ...
- 【效能提升】我们排查一个bug的过程是怎么样的?
背景 最近发现团队中一些同学对如何排查一个bug,思路不够清晰.本文随笔整理:常规情况下,我们是如何排查一个bug的. 1. 弄清楚问题 有些人看到"弄清楚问题",可能会觉得好笑, ...
- 机器学习 | 强化学习(2) | 动态规划求解(Planning by Dynamic Programming)
动态规划求解(Planning by Dynamic Programming) 动态规划概论 动态(Dynamic):序列性又或是时序性的问题部分 规划(Programming):最优化一个程序(Pr ...
- go、thinkphp8、webman数据读取并发测试、性能测试
前期准备:本地搭建程序运行所需环境,分别编写go,thinkphp8和webman程序,确保程序运行正常,新建mysql的student表,模拟存储学生信息,共计3646条数据,分别使用go语言.th ...
- AtCoder Beginner Contest 396-e
原题链接 思路 看到这道题,很明显就能发现这道题其实跟图论有关,将\(A\)数组看成一张无向图,每一个节点\(i\)的点权就是\(A_i\),每两个节点\(i\)和\(j\)之间的边权就是\(A_i ...
- 关于我这周的kotlin的学习:
今天学习了kotlin方法的参数和一些lambda的一些知识,其中也是和我们上次日报中讲的方法一样,有三种分类,默认参数,具名参数,可变数量的参数.和以前一样,我们举个例子来理解这个知识点:先是默认方 ...
- 【记录】C/C++-关于I/O的坑与教训
吐槽 每每读取字符串时,倘若稍有灵活的操作,总会遇上诡异奇怪的事情.究其原因,就是没完全理解一些基本读写函数的机制.这次做Uva227就把I/O上的问题全暴露出来了.想来还是应该记录一些经验教训. 记 ...
- Golang 入门 : 常量
常量 相对于变量而言,常量是在程序使用过程中,不会改变的数据.有些地方你需要将定义好的常量重复使用,代码中你不允许它的值改变.例如 圆周率 在程序执行过程中不会改变. 常量的声明 const Pi f ...