WPF学习 - 自定义Panel
阅读原文时间:2023年09月05日阅读:1

WPF中的Panel(面板),是继承自FrameworkElement的抽象类,表示一个可以用来排列子元素的面板。

在WPF中,一种预设了几种常用的面板,如Grid、StackPanel、WrapPanel等。他们都是继承自Panel类,并拥有自己的排列子元素的逻辑。

因此,想要自定义一个Panel,核心的问题就是如何排列子元素。

例如,我们做一个轴排列的元素,即元素沿着X、Y轴排列。我们定义,以面板宽度(Width)或者高度(Height)的中点,为坐标原点,水平向右为X轴,垂直向下位Y轴。如下图所示

先上源代码:

后代代码:

1 public class AxisPanel:Panel
2 {
3 internal static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
4 "Oritentation",typeof(Orientation),typeof(AxisPanel),new FrameworkPropertyMetadata(Orientation.Horizontal,FrameworkPropertyMetadataOptions.AffectsArrange));
5
6
7 ///

8 /// 指示子元素的布局方向 9 ///
10 public Orientation Orientation
11 {
12 get => (Orientation)GetValue(OrientationProperty);
13 set => SetValue(OrientationProperty, value);
14 }
15
16
17 /// 18 /// 测量子元素,以确定自己的DesiredSize。 19 /// 此方法由父级元素自动调用 20 ///
21 /// 父级元素提供给该面板的可用空间尺寸
22 /// 此面板对象需要的尺寸(DesiredSize)
23 protected override Size MeasureOverride(Size availableSize)
24 {
25 double width = 0, height = 0;
26 switch(Orientation)
27 {
28 case Orientation.Horizontal:
29 // 水平布局
30 foreach(UIElement child in Children)
31 {
32 child.Measure(availableSize);
33 width += child.DesiredSize.Width; // 计算面板需要的宽度;
34
35 if(child.DesiredSize.Height > height) // 计算面板需要的高度:为所有元素中最大的高度
36 {
37 height = child.DesiredSize.Height;
38 }
39 }
40 break;
41
42 case Orientation.Vertical:
43 // 垂直布局
44 foreach(UIElement child in Children)
45 {
46 child.Measure(availableSize);
47 height += child.DesiredSize.Height; // 计算面板需要的高度
48
49 if(child.DesiredSize.Width > width)
50 {
51 width = child.DesiredSize.Width; // 计算面板需要宽度:为所有元素中最大的宽度
52 }
53 }
54 break;
55 }
56
57 return new Size(width, height);
58 }
59
60
61
62 /// 63 /// 排列子元素 64 /// 此方法由父级元素自动调用 65 ///
66 /// 父级元素提供给该面板用于布局的最终尺寸。
67 ///
68 protected override Size ArrangeOverride(Size finalSize)
69 {
70 double totalWidth = 0, totalHeight = 0; // 面板的总宽度、高度
71 switch(Orientation)
72 {
73 case Orientation.Horizontal: // 水平排列:需要计算子元素左上角的坐标点,已经用于排列子元素的区域大小
74 double x1, y1; // 子元素左上角点的坐标
75 for (int i=0;i<Children.Count;i++)
76 {
77 x1 = totalWidth; // 子元素的x坐标,应该为总宽度的值
78 y1 = (finalSize.Height - Children[i].DesiredSize.Height) / 2; // 子元素的y坐标,始终保存在轴上
79 totalWidth += Children[i].DesiredSize.Width; // 总宽度增加
80 Rect rect = new(x1, y1, Children[i].DesiredSize.Width, Children[i].DesiredSize.Height); // 放置子元素的矩形区域
81 Children[i].Arrange(rect); // 放置子元素
82 }
83 break;
84
85 case Orientation.Vertical:
86 double x2, y2=0;
87
88 for (int i = 0; i < Children.Count;i++)
89 {
90 x2 = (finalSize.Width - Children[i].DesiredSize.Width) / 2;
91 y2 = totalHeight;
92 totalHeight += Children[i].DesiredSize.Height; // 所有子元素的总高度
93 Rect rect2 = new(x2, y2, Children[i].DesiredSize.Width, Children[i].DesiredSize.Height);
94 Children[i].Arrange(rect2);
95 }
96 break;
97 }
98 return finalSize;
99 }
100 }

前端代码:

1 2

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章