Expression Blend & Silverlight 中的相框控件






4.94/5 (36投票s)
如何在 Expression Blend 中从头开始构建第一个可重用控件。
引言
欢迎阅读我的第三篇 Expression Blend 和 Silverlight 初学者教程。
(感谢 Andrew Rissing 的新增加 Style Brushes - 请看这里!)
向一些读者致歉,偏离了按钮主题,但 Blend 还有更多内容!
但它绝对 不是 相框!
虽然 相框 将是构建我们的第一个 控件 的绝佳机会。
控件 基本上是一个可重用的 资产,具有预定义的 属性 和 样式。
概述
一位开发人员朋友惊慌失措地来找我,说他需要一个带“斜接”角(45 度)的相框,用于他第二天要演示的演示文稿。他自己尝试快速创建,但在处理相框的斜接角时遇到了问题。
他可能还想:为什么要养狗却自己叫?(英语表达)
所以我为他临时拼凑了一些东西,但作为设计师,我关心相框将要使用的上下文,即会使用什么颜色,相框会有多厚,以及什么样的轮廓最好看。因此,我想确保这些都易于他编辑,并且我创建的相框(也署了我的名字)会尽可能地好看。(我们设计师对我们的作品能最好地呈现非常敏感——抱歉!)
所以在制作 相框 的同时,我意识到这将是一个极好的初学者教程,关于制作您的第一个 控件。
在开始本教程之前,我建议您阅读我之前的 CodeProject 教程
我已将本教程分为几个部分,以便于查阅
第一节 - 设置基本框架
在 Expression Blend 中创建一个新的 Silverlight 项目,并将其命名为“PictureFrame
”之类的名称。
使用 选择工具,大致设置一些 网格 分隔线,如下所示
(不要担心比例,我们稍后会处理。)
现在选择 矩形工具 并拖出一个 矩形 以填充左上角的正方形。
确保 边距 都设置为 0 并删除 描边。
将 填充 设置为在背景上突出的颜色(我选择了亮绿色)。
右键单击 矩形,然后选择 路径 > 转换为路径。
(我还将 LayoutRoot 网格 的颜色更改为米白色,以便本教程更清晰。)
从左侧工具栏中选择 钢笔工具,然后单击 Rectangle
(正方形)的左下角点以将其删除。
(这也可以通过使用 直接选择 工具,选择节点/点并删除它来实现。)
选择新创建的 Triangle
并使用 复制 和 粘贴 复制它。
现在将复制的 Triangle
移动到 Grid
的右上角正方形,并确保 Margins
设置为 0
。
接下来,在 属性 选项卡的 Transform
部分,沿 X 轴 翻转 三角形。
再次选择 矩形工具,然后拖出一个 矩形 以填充 2 个 三角形 之间的 网格 中间部分。
确保 矩形 的 边距 设置为 0,并且 描边 和 填充 与 三角形 匹配。
在 对象和时间轴 中,重命名 三个 新元素,如下图所示
选择这 三个 元素并使用 复制 和 粘贴 复制它们。
将复制的元素移动到 网格 的底部,并沿 Y 轴 翻转 它们以反转它们。
确保 边距 设置为 0,并将这些元素重命名为 BottomLeftMask
、BottomRightMask
和 BottomMiddleMask
。
复制更多这些元素并填充侧面部分,如下所示。
翻转 三角形 元素以适应并调整 Rectangles
的大小 - 不要 旋转 任何元素!
(我已将侧面元素的 填充 颜色更改为蓝色,以便更清晰。)
确保所有 边距 都设置为 0,并根据它们在 Grid
中的位置重命名元素。
第二节 - 框架造型
现在我们有了 框架 的基本组件,让我们让它看起来更吸引人一些。
选择 TopMiddleMask
元素并将 填充 设置为 线性渐变,如下所示
(在 色带 上,黑色 渐变停止点 在 0 和 100 处,白色 渐变停止点 在 色带 上的 40 处。)
现在在 填充 的 高级属性 中,选择 转换为新资源。
在弹出的窗口中,将此新资源命名为“VerticalGradient
”。
现在选择其余的 顶部 和 底部 元素,并将此新创建的资源应用于每个元素的 填充。
接下来重复该过程,为所有侧面元素设置一个 HorizontalGradient
资源。
根据您移动和 翻转 元素的方式,您可能会得到类似这样的结果
请注意,某些侧面元素的渐变不匹配。
(我特意偏移了渐变的白色中心,以显示并确保我们所有元素都正确对齐。)
如果您的项目看起来像上面这样,最简单的重新对齐所有元素的方法是
翻转 LeftMiddleMask
和 RightMiddleMask
元素,并反转 HorizontalGradient
资源的 渐变停止点 方向。不幸的是,这意味着白色 渐变停止点 现在设置在 Ribbon
上的 60 处,并且与 VerticalGradient
资源不匹配。
所以取而代之的是
我仍然会 翻转 LeftMiddleMask
和 RightMiddleMask
元素,并使用 渐变工具 使 箭头 指向相反方向。
这也可以通过以下方式完成
通过打开 HorizontalGradient
资源的高级属性,并将 StartPoint
更改为 1
,EndPoint
更改为 0
。
现在您应该有一个四周都带有匹配 渐变 的框架。
如果您弄乱了,只需下载并打开下面的文件即可回到正轨。
第三节 - 转换为控件
我真正想做的是给这个 相框 添加一些颜色,但我不想在 渐变 中设置它,因为我必须单独调整 渐变停止点,这很麻烦且耗时。特别是如果我通过添加更多 渐变停止点 来为 相框 添加更多细节。
相反,我希望在一个地方控制我们的 相框 的颜色。就像我们在我之前的教程中为“样式”所做的那样(构建更好的按钮 和 街机按钮)
但目前我们没有 样式,只是一组元素。所以我们需要以某种方式将这些元素组合起来,以便它们都被打包在一个具有 样式 的 模板 中!
这真的很容易,我们只需要考虑哪种 控件模板 最适合我们的 相框。如果您看过我之前的教程,我们已经玩过 按钮控件、它的 样式 和它的 模板。
为简单起见,并且因为这些教程是针对初学者的,我将按钮称为 UserControl
,但它不是! 按钮是 Control
,可以被视为 UserControl
的一部分——这就是您目前需要知道的一切!
当我们制作 Control
时,我们需要以现有 Control
为基础,这样 Blend 才能提供一些基本 属性。相框 显然不是按钮,因此不需要按钮所具有的所有功能。所以即使我可以将这个 相框 基于按钮 Control
,那也不合适。
相反,我们应该寻找最基本的 Control
来满足我们 相框 的需求。为此,我选择使用“ContentControl
”作为我们 相框 的基础。
所以在 对象和时间轴 中,右键单击 LayoutRoot 网格,然后选择 制作成控件。
在弹出窗口的 搜索 区域中,输入“content”以过滤所有可用 控件。
然后选择结果窗口中的“ContentControl
”。
在 名称 (键) 字段中,将您的新 控件 命名为“PictureFrameControl
”之类的名称,然后单击 确定。
注意:我特意避免将其命名为“FrameControl”。因为 Blend 已经有一个名为“Frame”的 控件
(FrameControl 是一个带有附加导航的 ContentControl,此处不需要。)
您可以将您的 控件 命名为任何您喜欢的名称,但对于可能使用或引用它的所有人来说,清晰度应该是您的首要考虑!
希望您已经注意到,在 对象和时间轴 中,我们现在位于新 控件 的 模板 中。画板 的左上角也已更改,以显示我们位于 PictureFrameControl
的 模板 中。我们现在还拥有一个 ContentPresenter
作为我们 Control
的一部分,因为这是 ContentControl
的默认组件。
在 画板 中,ContentPresenter
当前被遮挡,因为它位于我们 Control
的左上角。
所以选择 ContentPresenter
并在 Artboard
中,将其拖到 Grid
的中心部分。
重置 边距,使 ContentPresenter
位于 Grid
中心部分的左上角。
就这样,关于制作您自己的 Control
!
第四节 - 整形和绑定
现在我们有了 Style
,可以考虑为我们的 Control
添加一些颜色,并控制我们 相框 的厚度。
所以首先,转到我们 PictureFrameControl
的 Style
,并为 Fill
设置一个漂亮的颜色。(我选择了 Blue
。)
现在回到我们 Control
的 Template
,从左侧工具栏中选择 矩形工具。
然后在 Artboard
中,拖出一个 Rectangle
以填充顶行的所有三个部分,如下图所示。
注意: 为了本截图的清晰度,我暂时将此 矩形 的 填充 设置为 红色。
将此 Rectangle
重命名为“TopBGround
”并删除 Stroke
。
现在将 填充 设置为 模板绑定 > BorderBrush。
对底行和两侧列重复此操作,分别命名为“BottomBGround
”、“LeftBGround
”和“RightBGround
”。
在 对象和时间轴 中,将这 四个 新元素移动到列表的顶部。
这样它们就在所有 渐变(蒙版)元素的后面。
现在在 对象和时间轴 中,选择所有 渐变(蒙版)元素,并将 不透明度 设置为 50%。
运气好的话,您的 相框 应该看起来像下图所示
现在这很漂亮,但 框架 相当笨重,所以接下来让我们解决这个问题。我们通过调整一开始设置的 行 和 列 分隔线来调整 框架 厚度并没有错。但我们可以做得比那好得多!!!
如何设置 框架 厚度,使其受 样式 的 边框 属性控制?这将使其更容易控制和调整以满足我们未来的需求。遗憾的是,在 Blend 3 中,我们无法直观地选择我们希望 绑定(链接到)的边框属性。相反,我们需要使用 自定义表达式 来 绑定 到 样式 的 边框 属性的 上、下、左 和 右。
因此选择 TopBGround
元素,然后在 高度 的 高级属性 中,选择 自定义表达式。
在弹出窗口中输入:{Binding BorderThickness.Top, RelativeSource={RelativeSource TemplatedParent}}
(不用担心理解此 表达式 的表示法,只需注意我们正在 绑定 到 BorderThickness.Top。)
对 BottomBGround
元素的 Height
重复此过程,但将 BorderThickness.Top
更改为 BorderThickness.Bottom
。
现在将 LeftBGround
和 RightBGround
元素的 Width
分别设置为 BorderThickness.Left
和 BorderThickness.Right
。
相框 的 Blue
背景消失了,这是因为 Style
的 边框厚度 设置为 0。
所以转到 样式 并将所有边的 边框厚度 设置为 50。
这应该会给您一个看起来像下图的 相框
虽然这是一个有趣的图像,但还不是我们想要的。
我们希望我们的 Blue
背景元素从外向中心生长。
所以回到 Template
中,选择 TopBGround
元素并将 VerticalAlignment
设置为 Top
。
接下来选择 BottomBGround
元素并将 VerticalAlignment
设置为 Bottom
。
现在将 LeftBGround
和 RightBGround
元素分别设置为 Left
和 Right
的 HorizontalAlignment
。
现在您的 相框 应该看起来像下图所示
(有趣,但还不是我们想要的。)
网格 分隔线当前设置为 星形(未锁定挂锁),这意味着它们与整体比例成比例。
如果您阅读过我的 街机按钮 教程,您可能还记得我说过这些 网格 分隔线有 三种 状态。
星形、固定 和 自动调整大小。
我们想要 自动调整大小,以便 网格 分隔线会根据该部分/分区内元素的需求进行放大或缩小。
因此,双击 第 1 和 第 3 行 和 列 分隔线,将它们更改为 自动调整大小,并与下图匹配。
变化很小(如果有什么变化的话),这是因为 Blend 已自动为这些 行 和 列 大小应用了 最小值。
这有时非常方便,但对于我们的需求来说有点麻烦...
要删除这些 最小 设置,我们需要转到 LayoutRoot
元素的 行 和 列定义。
这些可以在 布局 部分的 高级 部分和 定义编辑器 的 高级 部分找到。
(为了本教程,我已将此窗口缩小。)
但更简单的方法是选择 LayoutRoot
元素并直接编辑 XAML。
删除 应用于 列 和 行定义 的 MinWidth
和 MinHeight
参数。
这样您的 XAML 看起来像下图所示
既然我们在这里查看 XAML,值得注意的是
这个 PictureFrame“控件” 的 “控件”模板 是基于“ContentControl
”的 TargetType
。
但回到解决 框架厚度 的问题...
现在,尽管我们已经删除了这些 最小 设置用于我们的 列 和 行 大小,但 画板 中没有任何变化。
我们的 相框 厚度保持不变,原因似乎不清楚...
嗯...
第五节 - 路径和矢量图形数据
从本节标题您可能已经猜到是什么阻止了我们的 Frame
厚度调整大小。正是 Path
元素阻止了我们的 Column
和 Row
分隔线调整大小以适应 Style
的 Border
参数。所以让我们看看这些,以及它们是如何工作的。
任何熟悉 矢量图形 的人都会知道,构成 矢量图形 的所有点或线彼此都是相对的。但您可能从未真正关心过,它们有一个默认的大小或比例。当您打开一个 矢量图形 时,它会根据该文件中描述的单位进行大小调整。而 Blend 也做同样的事情,所以让我们看看这些数据。
选择一个 Path
元素,例如 TopLeftMask
元素,并查看 XAML 代码。
在下图中,我截取了我们感兴趣的代码片段。
查看:"Data="M0,0 L120,0 L120,120 z"
这都意味着什么?
嗯,基本上从左上角“0,0”的起始点开始,沿 X 轴延伸“120”的距离,沿 Y 轴延伸“0”的距离。定义此点后,从相同的起始点定义下一点,沿 X 轴“120”,沿 Y 轴“120”。
如果包含起始点,这定义了 3 个点,这是定义三角形所需的所有点。这些距离在 Blend 中以像素为单位定义,这指定了构成我们 三角形 角的 路径 的默认大小。
因此,Blend 将这些视为这些元素应该显示或绘制的 最小 大小。所以正是 路径 表面上阻止了我们的 列 和 行 分隔线遵循我们在 样式 中设置的 边框 厚度。
在这个例子中,我们不关心这些 三角形 以什么 比例 绘制,只关心它们是三角形并且比例正确。所以我们可以将第一个点设置在 X 轴上 1 像素处,第二个点设置在 X 轴上 1 像素处和 Y 轴上 1 像素处。加上我们的起始点,我们有 3 个点,并且我们的三角形比例正确。
但这将意味着我们的 边框(框架厚度)的 最小 尺寸将是 1 像素。如果我们的 相框 只有 3 条或更少的边,那就不理想了。相反,如果我们把 三角形 的 比例 设置为 0.1 像素,会更有意义,因为这在渲染成像素时相当于 0。比例将是相同的,而这正是我们在 相框 中所关心的。
所以在 XAML 中,选择 "Data="M0,0 L120,0 L120,120"",并使用 编辑 菜单中的替换功能。
更改为 "Data="M0,0 L0.1,0 L0.1,0.1 z"",并 全部替换,如下图所示
仿佛魔法一般,画板 中的 相框厚度 更新,看起来像下图所示
您现在拥有一个功能齐全的相框 控件,只需稍作修饰即可使其整洁。
但是,您可以随意退出 模板 并尝试调整 控件 的 边框厚度。
第六节 - 最后润色
在 Template
中,选择 LayoutRoot
元素并将其 模板绑定 到“Background
”。
选择 ContentPresenter
并将其 模板绑定 到 Style
的 Padding
。
在 Style
中,将 Background
和 BorderBrush
颜色设置为您喜欢的口味。
(我建议您将 Background 设置为“No Brush”(透明)。)
如果需要,应用一些 Padding 将 ContentPresenter
与 Frame
边缘隔开。
就这样了!
第七节 - 附加功能
希望您能意识到,可以通过调整 水平 和 垂直渐变 来改变 框架 轮廓。以及 渐变停止点 的 Alpha 值和整体元素 不透明度。但在您开始操作和调整这些之前,我建议您复制一份 相框“样式”。这样您就可以拥有多个 相框“样式”,每个样式具有不同的 框架 轮廓。
要进行复制,请使用“Return Scope”退出 模板 和 样式。
选择 相框,然后从 对象 菜单中,选择 编辑样式 > 编辑副本。
这将保留您为以前的 样式 设置的所有参数不变。您现在对 样式 所做的任何更新将仅应用于新 样式。但是,这不适用于 水平 和 垂直渐变,因为它们不包含在 样式 中。这些 资源 是 UserControl 的一部分,简单来说,就是您的整个页面。所以如果您更改这些 资源,更新将应用于两个 相框“样式”,因为它们都引用了它们。
显而易见的简单解决方案是复制这些 资源,然后为其中一个 样式 重命名并重新引用它们。您可能还会认为,如果我们可以向 样式 添加额外的画笔,那将非常酷。因为那样 水平 和 垂直渐变 就会很好地封装在 样式 中。我希望它就是那么简单,但它需要开发人员的帮助才能在 样式 中获得更多画笔。他们本质上会做的是从 ContentControl 继承并定义附加 功能。
使其成为 CustomContentControl
而不是我们可以拖放到任何旧 ContentControl
上的 Style
。
所以你必须判断,这真的值得吗?
对 Andrew Rissing 来说是值得的!!!他慷慨地介入并以“附加属性”的形式将这些 样式 添加到了 PictureFrameControl
(CustomContentControl
) 中。我们在 Blend 中使其正确初始化时遇到了一些小问题,因此如果您遇到任何初始问题,请务必 重新构建(或者可能 运行、关闭 并 重新打开)。但我相当确定一切都正常! :-)
非常感谢 Andrew,你真棒!!!您可以在这里找到 Andrew Rissing 的:附加依赖属性(文章/提示)。
(关于这些额外 画笔 的更多讨论可以在本教程后面的“推测”部分找到。)
还有一件事需要考虑,当我之前选择 ContentControl
作为我的 Control
的基础时。ContentControl
是一个 基类,其他 Controls,如 FrameControl
继承自 ContentControl
。(想象一下 基类 是基础,Controls 在这个基础上构建,为现有功能添加额外功能)。这意味着大多数继承自 ContentControl
的东西都将能够应用我们的 PictureFrameControl Style
。在 LayoutRoot(页面上)放置一个 Frame Control,看看您是否可以应用我们为 ContentControl
创建的 Style
。
不错吧?
但是,如果我将我的 PictureFrameControl
基于 FrameControl
,我可能无法正确地将 Style
应用到 ContentControl
。因为 FrameControl
可能在 Style
中定义了 ContentControl Style
中没有的附加功能。这在这个例子中可能不是问题,但它可能会成为问题,这也是我选择将我的 Control
基于 Base Class
的原因。
这还允许其他一些事情,我将用非常简单的术语来传达这个概念,那就是
通过将 Style
放置在 基类 中,我们拥有该 Style 和继承对象(例如 FrameControl
)的 Style 可供操作。因此,我们可以设置 基类 中的 Style
,并在继承对象的 Style
中覆盖其中一些 Style
属性。(如果您的所有对象/控件 共享相似的“主题”或 Style,并且可以在更高层次上针对个别类型的 控件 进行调整,那就太棒了。)
(希望这说得通,不要太深奥!)
推测:根据原始文章修改(在 Andrew Rissing 创建额外画笔之前)
考虑一下:您多久会去寻找市场上最时髦的 相框控件?我只会在您真正需要此功能时建议,例如图片库应用程序。
还存在这些 画笔 “附加属性”出现在每个 控件 和您的应用程序中的问题。这可能会让以后编辑应用程序的人感到困惑。他们怎么知道只有 PictureFrameControl
会支持这些画笔?
虽然额外的画笔很棒,但我可能不会使用它们,除非我确实需要大量这种 控件 的 样式。我不知道这些额外的画笔在大型项目中会有何反应。因此,如果您的应用程序中 只有少数 渐变,我个人会使用资源,以确保安全。因为减少任何损坏风险是件好事,也许是值得承担的开销。并且,我非常尊重 Andrew,但我建议任何设计师在实施高级(ExtraBrushes
)之前与他们的开发人员沟通。但作为设计工具,高级 控件 非常出色,可以非常轻松地操作框架轮廓和颜色提示。
现在最后一件需要考虑的关于这些 渐变资源 的事情是光线方向。光线是否来自标准的 315 度(钟面上的 10:30)?如果是这样,那么每个 框架样式 实际上需要 4 个渐变资源。因为 顶部 和 底部 元素需要在 渐变 的相对两侧有高光,侧面 渐变 也是如此。
在我们急于添加四个额外的 画笔 之前,我们可以考虑在现有叠加层之上设置一套全新的 叠加层(蒙版)。(只是为了不影响现有 资源。)但根据我们在现有 资源 中设置的轮廓,它会改变附加 叠加层 中所需的高光或低光的轮廓点。
所以如果我们想要一个倾斜的光源,我们就只能使用 4 个 渐变资源。
第八节 - 部署和重用
将此 PictureFrameControl
放在这个项目中没有任何问题。当我们需要它时,我们可以简单地 复制 和 粘贴 到另一个项目中。但更有意义的是,将其作为自己的 资源 存储起来,将其放置在 资源字典 中。这样,当我们想要这种类型的 控件 时,我们只需将相关的 资源字典 添加到项目文件中。这非常简单,但只要您知道如何操作,一切都很容易!
在 文件 菜单中,选择 新建项,然后会弹出一个窗口,如下图所示
选择 资源字典,将其命名为“PictureFrames.xaml”,然后点击 确定。
现在转到右侧的 资源 选项卡,并确保所有内容都已展开。
现在选择“PictureFrameControl”样式 并将其拖到 PictureFrames.xaml 上。
渐变资源 会自动跟随,因为它们被 样式 引用。
现在您应该能够使用右键单击 删除 来删除 UserControl 中的 样式 和 资源。
查看 项目 选项卡,您会注意到现在有一个名为“PictureFrames.xaml”的文件。
这是您的 控件 现在存储和被项目引用的位置。
因此,如果您想将此 控件 添加到另一个项目中,只需转到 项目 菜单并选择 添加现有项。
找到您的 PictureFrames.xaml,它位于您的 Project/PictureFrame/PictureFrame 目录中。
您的控件现在将在任何使用它的新项目中作为 Asset
可用,可在 资产 菜单中找到。
(在我们将它移动之前,它实际上已经在这里可用了,但我没想起来提一下。)
希望您能意识到,我们也可以对之前的两个按钮教程做同样的事情。
以便将它们打包在名为 Buttons.xaml 的 资源字典 中。
关于 资源字典 的最后一件事是编辑您的 控件!不用深入,在 UserControl
中编辑 控件模板 比在 资源字典 中容易得多!(稍后会有更多内容...)
暂时就这样吧,希望这有帮助,请给我的教程评分!
您的评论和支持对我们所有文章/教程作者来说意义重大!
以及对任何错误或需要进一步澄清的点的反馈...
祝好!
第九部分 - 来源
完成的 PictureFrameControl
,带有 2 个渐变资源 和 资源字典 引用
仅 PictureFrames.xaml(2 个渐变资源)作为 资源字典
完成的 PictureFrameControl
,带有 2 个 附加 “样式” 引用 画笔
历史
- 2010年3月29日:初始版本