一个浮点型 Margin 结构,现已加入 TypeConverter
一个 Margin 结构,可用于各种情况,如布局、绘图和打印。现已加入自定义 TypeConverter 和使用示例。
目录
引言
这是一个结构,类似于 .NET 2.0 中的 "http://msdn2.microsoft.com/en-us/library/system.windows.forms.padding.aspx">System.Windows.Forms.Padding
结构。但它使用浮点值,而不是整数。我不得不用到一些自定义绘图,这些绘图需要浮点数。因此,我创建了这个结构。
这是我在 CP(或任何编程文章)上的第一篇文章,而且英语不是我的母语,所以只能尽力而为……
现在它能正常工作了,我还制作了一个示例。
背景
margin 和 padding 的区别
在我看来,margin 用于“外部”,而 padding 用于“内部”。这与 Windows Forms 中的概念类似,控件(如按钮)具有两个属性。Margin
“指定此控件与另一个控件的 margin 之间的空间”。而 Padding
“指定控件的内部间距”。HTML 的用法大体相同。不过,这个结构可以同时用于这两种目的,就像 Padding
结构一样。
边的顺序
Margin
的边的顺序始终是 **左、上、右、下**。这与 Padding 结构以及矩形的 FromLTRB
方法相同。但这与 CSS 样式不同,我相信 CSS 样式使用 **上、右、下、左** 的顺序。LTRB 顺序用于构造函数和 ToString
。
Margin 成员
构造函数
有几个构造函数可用,大多数都一目了然。但是有一个构造函数不太清楚:new Margin(RectangleF outer, RectangleF inner)
。这会创建一个 new
Margin
,其各边是外部矩形和内部矩形之间的差值。您得到的是内部矩形相对于外部矩形的 margin,或者说是外部矩形相对于内部矩形的 padding。
属性
float Left
float Top
float Right
float Bottom
这些代表
Margin
的每一条边。它们对应于private
的l
、t
、r
、b
字段。float HorizontalAverage
float VerticalAverage
float Average
获取其中一个属性会返回边的平均值。设置一个属性会将相应的字段设置为该值。
Margin Negated
返回一个
Margin
,其各边与此Margin
的边相反(反转)。{1.4, -2, -19.5, 0}.Negated == {-1.4, 2, 19.5, 0}
Margin Absolute
返回一个
Margin
,其各边均大于或等于零。{1.4, -2, -19.5, 0}.Absolute == {1.4, 2, 19.5, 0}
Margin Rounded
返回一个
Margin
,其各边是此Margin
的各边四舍五入后的值。此操作是从零开始向外舍入,而不是银行家舍入。{1.4, -2, -19.5, 0}.Rounded == {1, -2, -20, 0}
bool IsRound
如果此
Margin
的所有边值都是圆整的,则返回true
。bool IsEmpty
如果此
Margin
的所有边都等于零,则返回true
。bool IsNaN
如果此
Margin
的一个或多个边是float.NaN
,则返回true
。请使用此项在某些计算后检查此Margin
是否有效。bool IsSymmetric
如果左边等于右边,并且顶边等于底边,则返回
true
。bool AllSidesEqual
如果此
Margin
的所有四条边值都相同,则返回true
。
Margin 本身的方法
我实现了一些常见的运算符重载和对应的静态方法。
- -
Negate
此操作与 Negated 属性执行相同的操作。
-{1.4, -2, -19.5, 0} == {-1.4, 2, 19.5, 0}
- +
Add
- -
Subtract
- *
Multiply
- /
Divide
这些操作将运算符应用于左侧
Margin
项的每个边。右侧可以是一个Margin
、一个float
或一个SizeF
。{1.4, -2, -19.5, 0} + 3.2F == {4.6, 1.2, -16.3, 3.2) {1.4, -2, -19.5, 0} * new SizeF(2F, 0.5F) == {2.8, -1, -39, 0} {1.4, -2, -19.5, 0} - {1.4, -2, -19.5, 0} == {0, 0, 0, 0} {1.4, -2, -19.5, 0} / 2F == {0.7, -1, 9.75, 0}
我还实现了一个
Translate
函数(没有运算符)。 Translate
此方法通过一个值“移动”Margin
。{0, 0, 0, 0}.Translate(1F, 3F) == {1, 3, -1, -3} {1.4, -2, -19.5, 0}.Translate(1F, 2F) == {2.4, -4, -20.5, -2}
其他方法
现在,所有这些属性、方法和运算符都很好,但也有一些使用 Margin
的方法会很方便。可用性方法数量有限;可以进行扩展,例如针对点。但是您有四种类型的点(矩形每个角一个),并且这四种点中的每一种都需要以不同的方式进行转换。这在待办事项列表中,当然也欢迎提出建议!
目前,我实现了这些方法:
InflateRectangle
DeflateRectangle
InflateSize
DeflateSize
它们使用
Margin
修改矩形和大小。
我还重写和重载了常用的 object 方法。
Equals
GetHashCode
ToString
如何使用
TypeConverter
经过一番折腾,我终于让 TypeConverter
工作起来了。设计器不再出现错误,或者属性突然重置 Margin
属性。
诀窍是尽可能少地在 MarginConverter
类中使用 Margin
类型。确切原因我也不知道,我认为这与设计器在构建之间管理类型的版本有关。因此,不要这样做:
// The current margin value
Margin margin = (Margin)value;
// The value of each side
float left = margin.Left;
float top = margin.Top;
float right = margin.Right;
float bottom = margin.Bottom;
您必须这样做:
// The current Margin type (from value)
Type type = value.GetType();
// The value of each side, retrieved with reflection
float left = (float)type.GetProperty("Left").GetValue(value, null);
float top = (float)type.GetProperty("Top").GetValue(value, null);
float right = (float)type.GetProperty("Right").GetValue(value, null);
float bottom = (float)type.GetProperty("Bottom").GetValue(value, null);
无论如何,现在它能正常工作了,至少对我来说是这样。如果您发现任何错误,请告诉我。
示例
附带了一个演示项目,它“打印”一页。它用单元格填充页面,您可以调整列数和行数,以及 margin 和 padding。
结论
这就是我这个小的 margin 结构,以及我的第一篇文章。希望您能找到一些用途。当然,非常欢迎留下评论!
历史记录
- 2007-03-15:版本 1.0 - 文章提交
- 2007-03-16:代码无更改。将文章标题从“
Margin
类”改为“Margin
结构”。真是的…… - 2007-03-29:版本 1.1 - 现在
Margin
有一个(可选的)MarginConverter
用于PropertyGrid
和设计器。还添加了一个示例。