- Silverlight 教程
- Silverlight - 首页
- Silverlight - 概述
- Silverlight - 环境设置
- Silverlight - 入门
- Silverlight - XAML 概述
- Silverlight - 项目类型
- Silverlight - 固定布局
- Silverlight - 动态布局
- 受约束与不受约束
- Silverlight - CSS
- Silverlight - 控件
- Silverlight - 按钮
- Silverlight - 内容模型
- Silverlight - ListBox
- Silverlight - 模板
- Silverlight - 可视状态
- Silverlight - 数据绑定
- Silverlight - 浏览器集成
- Silverlight - 浏览器外
- Silverlight - 应用程序、资源
- Silverlight - 文件访问
- Silverlight - 视图模型
- Silverlight - 输入处理
- Silverlight - 隔离存储
- Silverlight - 文本
- Silverlight - 动画
- Silverlight - 视频和音频
- Silverlight - 打印
- Silverlight 有用资源
- Silverlight 快速指南
- Silverlight - 有用资源
- Silverlight - 讨论
Silverlight 快速指南
Silverlight - 概述
欢迎使用 Silverlight 教程。Silverlight 是一个用于构建富互联网应用程序的平台。本教程将解释 Silverlight 背后的概念,并向您展示如何将其构建到您的 Web 应用程序中。完成本教程后,您将更好地理解使用 XAML 和 C# 的 Silverlight 应用程序。
什么是 Silverlight
Silverlight 是一种浏览器插件,旨在构建富互联网应用程序;这些应用程序像普通 Web 应用程序一样在浏览器中运行,但试图将用户界面提升到 HTML 可以达到的范围之外。例如,
Silverlight 是一个用于构建在各种操作系统上运行的、浏览器托管的富应用程序的框架。
它还可以与 HTML 共存。因此,Silverlight 可以增强现有的 Web 应用程序。
Silverlight 通过浏览器插件发挥其魔力。当您浏览到包含 Silverlight 内容的网页时,此浏览器插件会运行、执行代码并在页面中专门指定的区域呈现该内容。
重要的是,Silverlight 插件提供的环境比为普通网页提供支持的 HTML 和 JavaScript 的传统组合更丰富。
您可以创建播放视频、具有硬件加速的 3D 图形并使用矢量动画的 Silverlight 页面。
从开发人员的角度来看,Silverlight 最有趣的特性是它将 .NET Framework 编程模型引入 Web 应用程序的客户端。
Silverlight 旨在在网页内部运行,因此它可以作为浏览器插件运行。它提供用于渲染位图、矢量图形、高清视频和动画的图形服务。
您可以使用 C# 或 Visual Basic .NET 编写代码,并在 Web 浏览器中运行的代码上使用 .NET Framework 类库功能。
Silverlight 用户界面本身使用与 Windows Presentation Foundation (WPF) 非常相似的模型,WPF 是完整桌面 .NET Framework 中的用户界面框架。
如果您了解 WPF,那么 Silverlight 就很容易学习。Silverlight 的下载量比 .NET 小得多。它的大小大约是 .NET 的十分之一,因此只存在类库的一个子集,并且对 WPF 的模型进行了一些修改。
尽管规模缩小了,但经验丰富的 .NET 开发人员会立即在 Silverlight 中找到熟悉的感觉。
平台和浏览器
Silverlight 支持的平台和浏览器如下:-
Windows
Silverlight 支持 Windows,正如您对 Microsoft 产品的预期一样。它至少需要 Windows XP Service Pack 2 或最新版本的 Windows。
较旧的版本不受完全支持。例如,Silverlight 根本无法在 Windows ME 上运行,并且 Windows 2000 的支持有限。
对于浏览器,Silverlight 当然支持 Microsoft 自身的 Internet Explorer,并且支持 Firefox 和 Google Chrome 版本 4。
总的来说,Silverlight 支持常见的 Web 浏览器插件 API。它可以在比官方支持列表更广泛的浏览器中运行。
Mac
Silverlight 支持 Mac OS10,尽管 Silverlight 版本 2 或更高版本仅在基于 Intel 的 Mac 上运行。
在现代 Mac 上,Firefox 和 Safari 都受支持。
Linux
Microsoft 自身的 Silverlight 插件无法在 Linux 上运行,但 Mono 开源项目有一个名为 Moonlight 的分支,它是一个与 Silverlight 兼容的插件,可以在 Linux 上运行。
Moonlight 在 Firefox 中运行,有趣的是,它一直能够在独立模式下运行。
Mono 项目最初决定构建 Moonlight 的原因之一是,他们认为 Silverlight 将是一种有用的技术,可以用来构建在桌面上运行的用户界面小部件。
Silverlight - 环境设置
Microsoft 为 Silverlight 应用程序开发提供了两个重要的工具。它们是:-
- Visual Studio
- Expression Blend
目前,这两个工具都可以创建 Silverlight 项目,但事实是 Visual Studio 更受开发人员使用,而 Blend 仍然更常被设计人员使用。Microsoft 提供了 Visual Studio 的免费版本,您可以从 https://www.visualstudio.com 下载。在本教程中,我们将主要使用 Visual Studio。
安装
步骤 1 - 下载 Silverlight 后,运行安装程序。将显示以下对话框。
步骤 2 - 单击安装按钮,它将启动安装过程。
步骤 3 - Silverlight 成功安装后,您将看到以下对话框。
步骤 4 - 关闭此对话框,并在需要时重新启动计算机。
步骤 5 - 现在从开始菜单打开Visual Studio,这将打开如下所示的对话框。首次启动时,它需要一些时间进行准备。
步骤 6 - 接下来,您将看到 Visual Studio 的主窗口。
步骤 7 - 现在,要开始使用 Silverlight 应用程序,您还需要在您的计算机上安装 Silverlight 开发人员工具。从http://silverlight.dlservice.microsoft.com/download/8/E/7/8E7D9B4B-2088-4AED8356-20E65BE3EC91/40728.00/Silverlight_Developer_x64.exe下载并安装最新的 Silverlight 开发人员工具。
步骤 8 - 单击安装。安装需要一些时间。
步骤 9 - 安装完成后,您将看到以下消息。
步骤 10 - 现在您已准备好构建您的第一个 Silverlight 应用程序。单击关闭。
Silverlight - 入门
在本章中,我们将了解 Silverlight 的一个工作示例。我们需要两件事:-
首先,我们需要一个网页。Silverlight 旨在用于富互联网应用程序,它旨在作为网页的一部分在 Web 浏览器中运行。页面需要包含一个合适的标签来加载 Silverlight 插件。它还可以包含检测 Silverlight 是否已安装的逻辑,并在 Silverlight 不存在时提供一些后备用户界面。
我们需要做的第二件事是 Silverlight 内容本身。本教程将重点介绍 Silverlight 的 .NET 编程模型。我们将创建一个编译后的 Silverlight 应用程序,其中包含 XAML(我们用来定义 Silverlight 用户界面的模拟语言)和用 C# 编写的 .NET 代码的混合。
创建网页
使用 Silverlight 的最简单方法是创建一个带有 HTML 页面的普通网站,并且没有服务器端代码。让我们看一个非常简单的例子。
步骤 1 - 打开Visual Studio。单击文件菜单,指向新建,然后单击项目。
步骤 2 - 将打开新建项目对话框。在模板下,选择Visual C#,然后单击Silverlight。在右侧窗格中,选择 Silverlight 应用程序。
输入项目名称和硬盘驱动器上的保存位置,然后单击确定以创建项目。
Silverlight 项目本身只是构建 Silverlight 内容,而该内容只是构成整个 Web 应用程序的众多资产之一。
单击确定。
步骤 3 - 选中托管 Silverlight 应用程序复选框。默认值为 ASP.NET Web 应用程序项目。
步骤 4 - MS-Visual Studio 创建了两个项目,Silverlight 项目和 ASP.NET Web 应用程序。现在,我们确实需要一个 ASP.NET Web 应用程序。您可以在解决方案资源管理器窗口中看到它,如下所示。
任何可以通过 HTTP 提供内容的内容都可以,但这是Visual Studio,它理解 ASP.NET Web 技术,所以这就是它提供给我们的内容。
为了证明 Silverlight 不依赖于任何特定的服务器端技术,让我们删除此.aspx文件,只保留纯静态 HTML 文件。
步骤 5 - 右键单击 FirstExampleTestpage.aspx。从选项列表中,单击删除。
步骤 6 - 将FirstExampleTestPage.html设置为启动页面。
MainPage.xaml文件定义了 Silverlight 内容的用户界面。您可以直接编写 XAML 代码,也可以使用工具箱拖放不同的 UI 元素。
步骤 7 - 下面是在MainPage.xaml中的一段简单代码,其中Button和TextBlock定义在StackPanel内。
<UserControl x:Class = "FirstExample.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <StackPanel> <TextBlock x:Name = "TextMessage" Text = "Hello World!" Margin = "5"> </TextBlock> <Button x:Name = "ClickMe" Click = "ClickMe_Click" Content = "Click Me!" Margin = "5"> </Button> </StackPanel> </Grid> </UserControl>
步骤 8 - 此示例假设您已创建了一个名为ClickMe_Click的事件处理方法。以下是它在MainPage.xaml.cs文件中的样子。
using System.Windows; using System.Windows.Controls; namespace FirstExample { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void ClickMe_Click(object sender, RoutedEventArgs e) { TextMessage.Text = "Congratulations! you have created your first Silverlight Applicatoin"; } } }
步骤 9 - Silverlight 应用程序可以在任何已安装的浏览器上运行。
步骤 10 - 当上述代码编译并执行时,您将看到以下网页。
步骤 11 - 现在,当您单击单击我按钮时,它将更新TextBlock中的文本,如下所示。
我们建议您通过添加更多 UI 元素来执行上述示例。
Silverlight - XAML 概述
在使用 Silverlight 时,您会遇到的第一件事之一是 XAML。XAML 代表可扩展应用程序标记语言。它是一种基于 XML 的简单且声明性的语言。
在 XAML 中,创建、初始化和设置具有层次关系的对象的属性非常容易。
它主要用于设计 GUI。
它也可以用于其他目的,例如,在工作流基础中声明工作流。
基本语法
当您创建一个新的 Silverlight 项目时,您将在MainPage.xaml中看到一些默认的 XAML 代码,如下所示。
<UserControl x:Class = "FirstExample.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> </Grid> </UserControl>
您可以看到上面给出的 XAML 文件提到了不同类型的信息;下面给出的表中简要描述了所有这些信息。
信息 | 描述 |
---|---|
<UserControl> | 提供定义一个封装现有控件并提供自身逻辑的新控件的基类。 |
x:Class = "FirstExample.MainPage" | 这是一个部分类声明,它将标记与在其中定义的代码隐藏部分类代码连接起来。 |
xmlns = "http://schemas.microsoft.com /winfx/2006/xaml/presentation" | 映射 Silverlight 客户端/框架的默认 XAML 命名空间。 |
xmlns:x = "http://schemas.microsoft.c om/winfx/2006/xaml" | XAML 语言的 XAML 命名空间,将其映射到 x: 前缀。 |
xmlns:d = "http://schemas.microsoft.com /expression/blend/2008" | XAML 命名空间用于设计器支持,特别是 Microsoft Visual Studio 和 Microsoft Expression Blend 中的 XAML 设计界面的设计器支持。 |
xmlns:mc = "http://schemas.openxmlforma ts.org/markup-compatibility/2006" | 指示并支持用于读取 XAML 的标记兼容模式。 |
> | 根对象的元素结束。 |
<Grid></Grid> | 这些是空网格对象的开始和结束标签。 |
</UserControl> | 关闭对象元素。 |
XAML 的语法规则与 XML 的语法规则几乎相同。如果您查看 XAML 文档,您会注意到它实际上是一个有效的 XML 文件。反之则不成立,因为在 XML 中,属性的值必须是字符串,而在 XAML 中它可以是不同的对象,这被称为属性元素语法。
对象元素的语法以左尖括号 (<) 开头,后跟对象的名称,例如 Button。
定义该对象元素的属性和特性。
对象元素必须以正斜杠 (/) 后跟右尖括号 (>) 立即关闭。
下面显示了一个没有子元素的简单对象的示例。
<Button/>
具有某些属性的对象元素示例 -
<Button Content = "Click Me" Height = "30" Width = "60"/>
定义属性的备用语法的示例(属性元素语法) -
<Button> <Button.Content>Click Me</Button.Content> <Button.Height>30</Button.Height> <Button.Width>60</Button.Width> </Button>
具有子元素的对象示例:StackPanel 包含 Textblock 作为子元素。
<StackPanel Orientation = "Horizontal"> <TextBlock Text = "Hello"/> </StackPanel/>
为什么 Silverlight 中要使用 XAML
XAML 最初并非为 Silverlight 而发明。它来自 WPF,即 Windows Presentation Foundation。Silverlight 通常被描述为 WPF 的子集。这并不完全正确,因为 Silverlight 可以执行 WPF 无法执行的操作。即使在功能重叠的地方,这两者在细节上也略有不同。
更准确地说,WPF 和 Silverlight 在许多方面非常相似。尽管存在差异,但查看 Silverlight 从 WPF 借用的 XAML 功能仍然很有帮助。例如,Silverlight 提供了位图和可缩放形状的图形基元。
它还提供用于渲染视频和音频的元素。
它具有简单的格式化文本支持,您可以动画化任何元素。如果您了解 WPF,则此功能集将非常熟悉。
有一点很重要,您不能获取 WPF XAML 并将其用于 Silverlight。
尽管存在相似之处,但您也会发现许多细微差别。
XAML 和代码隐藏
XAML 定义用户界面的外观和结构。但是,如果您希望应用程序在用户与之交互时执行任何有用的操作,则需要一些代码。
每个 XAML 文件通常都与一个源代码文件关联,我们将其称为代码隐藏。各种 Microsoft 框架都使用此术语。
代码隐藏通常需要使用 XAML 中定义的元素,以检索有关用户输入的信息或向用户显示信息。
在下面给出的 XAML 代码中,定义了TextBlock 和Button。默认情况下,当应用程序运行时,它将在网页上显示文本“Hello World!”和一个按钮。
<UserControl x:Class = "FirstExample.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <StackPanel> <TextBlock x:Name = "TextMessage" Text = "Hello World!" Margin = "5"> </TextBlock> <Button x:Name = "ClickMe" Click = "ClickMe_Click" Content = "Click Me!" Margin = "5"> </Button> </StackPanel> </Grid> </UserControl>
代码隐藏可以访问使用x:Name指令命名的任何元素。
命名元素通过代码隐藏中的字段可用,允许代码以通常的方式访问这些对象及其成员。
x:Prefix表示该名称不是普通属性。
x:Name是 XAML 编译器的一个特殊信号,表明我们希望在代码隐藏中访问此对象。
下面给出了按钮单击事件的实现,其中更新了TextBlock文本。
using System.Windows; using System.Windows.Controls; namespace FirstExample { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void ClickMe_Click(object sender, RoutedEventArgs e) { TextMessage.Text = "Congratulations! you have created your first Silverlight Applicatoin"; } } }
XAML 不是设计 UI 元素的唯一方法。您可以选择在 XAML 中声明对象,或者在代码中声明/编写。
XAML 是可选的,但尽管如此,它仍然是Silverlight设计的核心。
使用 XAML 编码的目标是使视觉设计人员能够直接创建用户界面元素。因此,Silverlight旨在使从标记控制用户界面的所有视觉方面成为可能。
Silverlight - 项目类型
如果您在 Visual Studio 中创建一个新项目,您将在对话框的右侧窗格中看到四种类型的项目。它们是 -
- Silverlight 应用程序
- Silverlight 类库
- 类库(可移植)
- Silverlight 导航应用程序
前两个,Silverlight 应用程序和Silverlight 类库,非常简单易懂。它们类似于经典 Windows 应用程序世界中的 DLL 中的可执行文件。由于 Silverlight 应用程序的部署方式,两者都构建 DLL。
从概念上讲,Silverlight 应用程序项目构建一个可以运行的程序,而类库项目构建一个旨在集成到其他应用程序中的库。
如果您计划构建多个应用程序并希望重用公共代码,则可以构建类库。如果您计划销售其他人将在其应用程序中使用的控件,那么库也是要构建的内容。
其他项目类型不太明显,因此我们将在本章后面详细介绍这些内容。
Silverlight Web 应用程序
Silverlight 应用程序是从 Web 下载的,因此您通常会与 Silverlight 项目关联一个 Web 项目。Visual Studio 有几个功能旨在管理这些项目之间的关系。
让我们再看一个简单的 Silverlight 应用程序项目示例。
步骤 1 - 打开Visual Studio。单击文件菜单,指向新建,然后单击项目。
步骤 2 - 将打开新建项目对话框。在模板下,选择Visual C#,然后单击Silverlight。在右侧窗格中,选择 Silverlight 应用程序。
输入项目名称和硬盘驱动器上的位置以保存您的项目。
Silverlight 项目本身只是构建 Silverlight 内容,而该内容只是构成整个 Web 应用程序的众多资产之一。
单击确定。
步骤 3 - 选中托管 Silverlight 应用程序复选框。默认值为 ASP.NET Web 应用程序项目。
步骤 4 - MS-Visual Studio 创建了两个项目,Silverlight 项目和 ASP.NET Web 应用程序。现在,我们需要一个 ASP.NET Web 应用程序。您可以在解决方案资源管理器窗口中看到它,如下所示。
任何可以通过 HTTP 提供内容的内容都可以,但这是Visual Studio,它理解 ASP.NET Web 技术,所以这就是它提供给我们的内容。
为了证明 Silverlight 不依赖于任何特定的服务器端技术,让我们删除此.aspx文件,只保留纯静态 HTML 文件。
步骤 5 - 右键单击 FirstExampleTestpage.aspx。从选项列表中,单击删除。
步骤 6 - 将FirstExampleTestPage.html设置为启动页面。
MainPage.xaml文件定义了 Silverlight 内容的用户界面。您可以直接编写 XAML 代码,也可以使用工具箱拖放不同的 UI 元素。
步骤 7 - 下面是在MainPage.xaml中的一段简单代码,其中Button和TextBlock定义在StackPanel内。
<UserControl x:Class = "FirstExample.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <StackPanel> <TextBlock x:Name = "TextMessage" Text = "Hello World!" Margin = "5"> </TextBlock> <Button x:Name = "ClickMe" Click = "ClickMe_Click" Content = "Click Me!" Margin = "5"> </Button> </StackPanel> </Grid> </UserControl>
步骤 8 - 此示例假设您已创建了一个名为ClickMe_Click的事件处理方法。以下是它在MainPage.xaml.cs文件中的样子。
using System.Windows; using System.Windows.Controls; namespace FirstExample { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void ClickMe_Click(object sender, RoutedEventArgs e) { TextMessage.Text = "Congratulations! you have created your first Silverlight Applicatoin"; } } }
步骤 9 - Silverlight 应用程序可以在任何已安装的浏览器上运行。
步骤 10 - 当上述代码编译并执行时,您将看到以下网页。
Silverlight 导航应用程序
Silverlight 导航应用程序模板构建了一个类似于普通 Silverlight 应用程序的项目。这两种项目类型之间没有任何根本区别。导航模板仅包含一些您可以轻松添加的其他代码。顾名思义,它支持 Silverlight 应用程序内的类似 Web 的导航。
让我们创建一个导航应用程序。
步骤 1 - 在新建项目对话框的右侧窗格中选择Silverlight 导航应用程序。
步骤 2 - 按照您对 Silverlight Web 应用程序所做的设置进行操作。
步骤 3 - 点击确定按钮。将打开一个窗口,如下所示。
这些通常具有关联的 Web 项目,因此我们将拥有其中一个。它创建了前面描述的两个项目,但如您所见,默认用户界面看起来不那么空白了。
步骤 4 - 它提供了一个应用程序 Chrome,包括一个导航栏。该解决方案包含一些额外的文件。此样式文件定义了导航栏的外观。在此视图文件夹中,我们看到几个页面,以及一个显示错误的窗口。
如您所见,当您运行应用程序时,它会显示一个带有某些占位符内容的主页。
步骤 5 - 当您点击关于按钮时,它将导航到关于页面。
重要的是,您可以随后使用浏览器后退和前进按钮来回溯步骤。
通常,当您这样做时,Web 浏览器会从一个网页跳转到另一个网页,但此处不会。Silverlight 应用程序实际上并没有卸载;它保持运行,只是显示不同的内容。
因此,从浏览器的角度来看,它实际上都在一个网页上。Silverlight 对导航按钮进行了一些技巧,以确保在导航时网页不会卸载。
Silverlight - 固定布局
控件的布局对于应用程序可用性非常重要且至关重要。它用于在应用程序中排列一组 GUI 元素。在选择布局面板时,需要考虑某些重要事项。它们是 -
- 子元素的位置。
- 子元素的大小。
- 子元素彼此重叠的分层。
如果应用程序已在不同的屏幕分辨率上使用,则控件的固定像素排列不起作用。XAML 提供了一套丰富的内置布局面板,以适当的方式排列 GUI 元素。
我们将从查看简单的固定布局开始。然后,我们将查看 Silverlight 设计为支持的动态布局场景。我们将看到贯穿所有用户界面元素的布局相关属性和概念。
固定布局
Canvas元素提供了最简单的布局类型。Canvas面板是基本布局面板,其中可以使用相对于 Canvas 任何一侧(如左、右、上和下)的坐标明确定位子元素。
通常,Canvas用于 2D 图形元素(例如 Ellipse、Rectangle 等)。它不用于 UI 元素,因为在调整大小、本地化或缩放 XAML 应用程序时,指定绝对坐标会带来麻烦。
下面列出了Canvas类的常用属性。
序号 | 属性和描述 |
---|---|
1 | Background 获取或设置填充面板内容区域的 Brush。(继承自 Panel) |
2 | Children 获取此 Panel 的子元素的 UIElementCollection。(继承自 Panel。) |
3 | Height 获取或设置元素的建议高度。(继承自 FrameworkElement。) |
4 | ItemHeight 获取或设置一个值,该值指定 WrapPanel 中包含的所有项目的的高度。 |
5 | ItemWidth 获取或设置一个值,该值指定 WrapPanel 中包含的所有项目的宽度。 |
6 | LogicalChildren 获取一个枚举器,该枚举器可以迭代此 Panel 元素的逻辑子元素。(继承自 Panel。) |
7 | LogicalOrientation 面板的方向,如果面板仅支持单维度布局。(继承自 Panel。) |
8 | LeftProperty 标识 Canvas.Left XAML 附加属性。 |
9 | Margin 获取或设置元素的外边距。(继承自 FrameworkElement。) |
10 | Name 获取或设置元素的标识名称。名称提供了一个引用,以便代码隐藏(例如事件处理程序代码)在 XAML 处理器处理期间构造标记元素后引用它。(继承自 FrameworkElement。) |
11 | Orientation 获取或设置一个值,该值指定子内容排列的维度。 |
12 | Parent 获取此元素的逻辑父元素。(继承自 FrameworkElement。) |
13 | Resources 获取或设置本地定义的资源字典。(继承自 FrameworkElement。) |
14 | Style 获取或设置此元素渲染时使用的样式。(继承自 FrameworkElement。) |
15 | TopProperty 标识 Canvas.Top XAML 附加属性。 |
16 | Width 获取或设置元素的宽度。(继承自 FrameworkElement。) |
17 | ZIndexProperty 标识 Canvas.ZIndex XAML 附加属性。 |
以下是Canvas常用方法。
序号 | 方法及描述 |
---|---|
1 | GetLeft 获取目标元素的 Canvas.Left XAML 附加属性的值。 |
2 | GetTop 获取目标元素的 Canvas.Top XAML 附加属性的值。 |
3 | GetZIndex 获取目标元素的 Canvas.ZIndex XAML 附加属性的值。 |
4 | SetLeft 设置目标元素的 Canvas.Left XAML 附加属性的值。 |
5 | SetTop 设置目标元素的 Canvas.Top XAML 附加属性的值。 |
6 | SetZIndex 设置目标元素的 Canvas.ZIndex XAML 附加属性的值。 |
以下示例演示如何将子元素添加到Canvas中。以下是 XAML 实现,其中在 Canvas 中创建了一个 Ellipse,并带有不同的偏移属性。
<UserControl x:Class = "FirstExample.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <Canvas Width = "380" Height = "280" > <Ellipse Canvas.Left = "30" Canvas.Top = "30" Fill = "Gray" Width = "200" Height = "120" /> </Canvas> </Grid> </UserControl>
编译并执行上述代码后,您将看到以下输出。
Silverlight - 动态布局
Canvas是所有 Silverlight 布局面板中最不有趣的一个。其他面板支持动态布局,这意味着布局可以根据显示项目数量、显示信息的尺寸或用户调整浏览器大小导致的应用程序可用空间数量的变化进行调整。
Silverlight 提供了两个具有动态布局策略的面板。
StackPanel - 将元素垂直或水平排列成堆栈。
Grid - 提供灵活的网格状或表格状布局系统。
Stack Panel
Stack Panel 是 XAML 中一个简单而有用的布局面板。在Stack Panel中,子元素可以基于其方向属性水平或垂直排列成一行。它通常用于创建任何类型的列表时。ItemsControls 使用 Stack Panel。Menu、ListBox 和ComboBox 是它们的默认内部布局面板。
以下是StackPanel的常用属性。
序号 | 属性和描述 |
---|---|
1 | Background 获取或设置填充面板内容区域的 Brush。(继承自 Panel) |
2 | Children 获取此 Panel 的子元素的 UIElementCollection。(继承自 Panel。) |
3 | Height 获取或设置元素的建议高度。(继承自 FrameworkElement。) |
4 | ItemHeight 获取或设置一个值,该值指定 WrapPanel 中包含的所有项目的的高度。 |
5 | ItemWidth 获取或设置一个值,该值指定 WrapPanel 中包含的所有项目的宽度。 |
6 | LogicalChildren 获取一个枚举器,该枚举器可以迭代此 Panel 元素的逻辑子元素。(继承自 Panel。) |
7 | LogicalOrientation 面板的方向,如果面板仅支持单维度布局。(继承自 Panel。) |
8 | Margin 获取或设置元素的外边距。(继承自 FrameworkElement。) |
9 | Name 获取或设置元素的标识名称。名称提供了一个引用,以便代码隐藏(例如事件处理程序代码)在 XAML 处理器处理期间构造标记元素后引用它。(继承自 FrameworkElement。) |
10 | Orientation 获取或设置一个值,该值指定子内容排列的维度。 |
11 | Parent 获取此元素的逻辑父元素。(继承自 FrameworkElement。) |
12 | Resources 获取或设置本地定义的资源字典。(继承自 FrameworkElement。) |
13 | Style 获取或设置此元素渲染时使用的样式。(继承自 FrameworkElement。) |
14 | Width 获取或设置元素的宽度。(继承自 FrameworkElement。) |
以下示例演示如何将子元素添加到StackPanel中。以下是 XAML 实现,其中在 StackPanel 中创建了Buttons,并带有一些属性。
<UserControl x:Class = "DynamicLayout.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <StackPanel> <Button x:Name = "button" Content = "Button" Margin = "10" /> <Button x:Name = "button1" Content = "Button" Margin = "10"/> <Button x:Name = "button2" Content = "Button" Margin = "10"/> <Button x:Name = "button3" Content = "Button" Margin = "10"/> </StackPanel> </Grid> </UserControl>
编译并执行上述代码后,您将看到以下输出。
StackPanel 尝试为每个元素在堆叠方向上提供尽可能多的空间。
现在,如果您调整浏览器大小,您将看到按钮的宽度也发生了变化。
Grid
Grid 面板提供了一个灵活的区域,该区域由行和列组成。在Grid中,子元素可以以表格形式排列。可以通过使用Grid.Row 和Grid.Column 属性将元素添加到任何特定的行和列。默认情况下,Grid面板创建一行一列。多个行和列由RowDefinitions 和ColumnDefinitions 属性创建。行的高度和列的宽度可以通过以下三种方式定义:
固定值 - 为逻辑单位(1/96 英寸)分配固定大小。
Auto - 它将占用特定行/列中的控件所需的空间。
星号 (*) - 当Auto和固定大小填充后,它将占用剩余的空间。
以下是Grid类的常用属性。
序号 | 属性和描述 |
---|---|
1 | Background 获取或设置填充面板内容区域的 Brush。(继承自 Panel) |
2 | Children 获取此 Panel 的子元素的 UIElementCollection。(继承自 Panel。) |
3 | ColumnDefinitions 获取在此 Grid 实例上定义的 ColumnDefinition 对象列表。 |
4 | Height 获取或设置元素的建议高度。(继承自 FrameworkElement。) |
5 | ItemHeight 获取或设置一个值,该值指定 WrapPanel 中包含的所有项目的的高度。 |
6 | ItemWidth 获取或设置一个值,该值指定 WrapPanel 中包含的所有项目的宽度。 |
7 | Margin 获取或设置元素的外边距。(继承自 FrameworkElement。) |
8 | Name 获取或设置元素的标识名称。名称提供了一个引用,以便代码隐藏(例如事件处理程序代码)在 XAML 处理器处理期间构造标记元素后引用它。(继承自 FrameworkElement。) |
9 | Orientation 获取或设置一个值,该值指定子内容排列的维度。 |
10 | Parent 获取此元素的逻辑父元素。(继承自 FrameworkElement。) |
11 | Resources 获取或设置本地定义的资源字典。(继承自 FrameworkElement。) |
12 | RowDefinitions 获取在此 Grid 实例上定义的 RowDefinition 对象列表。 |
13 | Style 获取或设置此元素渲染时使用的样式。(继承自 FrameworkElement。) |
14 | Width 获取或设置元素的宽度。(继承自 FrameworkElement。) |
以下是Grid类的常用方法。
序号 | 方法及描述 |
---|---|
1 | GetColumn 从指定的 FrameworkElement 获取 Grid.Column XAML 附加属性的值。 |
2 | GetColumnSpan 从指定的 FrameworkElement 获取 Grid.ColumnSpan XAML 附加属性的值。 |
3 | GetRow 从指定的 FrameworkElement 获取 Grid.Row XAML 附加属性的值。 |
4 | SetColumn 设置指定 FrameworkElement 上 Grid.Column XAML 附加属性的值。 |
5 | SetRow 设置指定 FrameworkElement 上 Grid.Row XAML 附加属性的值。 |
6 | SetRowSpan 设置指定 FrameworkElement 上 Grid.RowSpan XAML 附加属性的值。 |
以下示例演示如何将子元素添加到 Grid 以表格形式指定它。以下是 XAML 实现,其中添加了一些 UI 元素。
<UserControl x:Class = "DynamicLayout.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <Grid.ColumnDefinitions> <ColumnDefinition Width = "130" /> <ColumnDefinition Width = "1*" /> <ColumnDefinition Width = "2*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height = "Auto" /> <RowDefinition Height = "50" /> </Grid.RowDefinitions> <TextBlock Grid.Column = "0" Grid.Row = "0" Text = "Content that no longer fits, not even close here" TextWrapping = "Wrap" /> <Button Grid.Column = "1" Grid.Row = "0" Content = "OK" /> <Ellipse Grid.Column = "1" Grid.Row = "1" Fill = "Aqua" /> <Rectangle Grid.Column = "2" Grid.Row = "1" Fill = "Orchid" RadiusX = "20" RadiusY = "20" /> </Grid> </UserControl>
第一列设置为固定大小。此列中的任何元素都将具有该宽度。Grid.Column 和Grid.Row 属性指定这些项目位于哪一行和哪一列,它们是基于 0 的属性。
第二列或第三列的宽度为1*和2*。这意味着它们共享在任何固定宽度和自动宽度列占用其空间后剩余的空间。此处1和2的意义在于,2*列获得的空间是1*列的两倍。
执行上述代码后,您将看到以下输出。
调整应用程序大小时,这两列的内容也会调整大小以匹配。顺便说一句,星号大小的行或列的绝对值无关紧要;只有比率很重要。
受约束与不受约束的布局
Silverlight 中的布局始终以两种模式之一发生,即受约束或不受约束。受约束的布局是指容器强制实施宽度或高度的布局。例如,Web 浏览器通常使用 CSS 始终确定 Silverlight 插件的整体尺寸。
一些重要的特性是:
顶级元素的布局在水平和垂直方向上都受到约束。无论它产生什么布局,最终都必须始终得到浏览器强制实施的大小结果。
某些元素最终具有不受约束的布局,这意味着这些元素可以自由选择自己的大小。例如,垂直StackPanel内的元素在垂直方向上不受约束。
StackPanel 将为它们提供所需的高度。事实上,即使没有足够的空间,它也会这样做。它会告诉元素它们拥有所需的高度,然后裁剪任何不适合的部分。
大多数 Silverlight 用户界面包含这两种布局样式的混合。无论其父级是否施加约束,StackPanel始终会在堆叠方向上执行不受约束的布局。当高度或宽度设置为Auto时,Grid 行或列也是如此。
假设您有一个元素,它位于一个强制实施固定水平宽度的容器内。默认情况下,您的元素将被拉伸以填充空间。如果将对齐方式设置为 Left、Right 或 Center,它将删除约束。
元素将仅占用其所需宽度。当然,您可以使用固定宽度或高度引入约束。
不受约束的布局有时称为根据内容调整大小,因为不受约束的元素的大小通常由其内容决定。
根据内容调整大小是 Silverlight 布局中的一个重要概念。它使布局能够根据正在显示的信息自适应。
序号 | 控件及描述 |
---|---|
1 | GridSplitter
约束可以来自包含的浏览器,也可以来自设计中的固定尺寸。但是,有时让用户施加约束也很有用。 |
2 | ScrollViewer
某些用户界面最终需要显示比可用空间所能容纳的更多信息。对此的一种常见解决方案是提供一个可滚动区域。Silverlight 使用 ScrollViewer 使此操作非常容易。 |
3 | Border
在布局用户界面时,另一个需要牢记的有用元素是 Border。 |
全屏模式
Silverlight 插件能够接管整个屏幕。您可以设置辅助类上的一个属性以进入全屏模式。但是,出于安全目的,有一些约束。为了防止网站能够随意接管屏幕,并执行一些恶意操作,例如伪造提示以要求用户输入密码。
要进入全屏模式,您需要从应用程序对象获取 Host.Content 属性,并将 IsFullScreen 属性设置为 true。
让我们来看一个简单的示例,该示例切换属性,以便它在全屏和普通模式之间来回切换。
<UserControl x:Class = "FullScreenExample.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Border BorderBrush = "Gray" BorderThickness = "4" CornerRadius = "30" Padding = "20"> <Border.Background> <LinearGradientBrush StartPoint = "0,0" EndPoint = "0,1"> <GradientStop Offset = "0" Color = "Wheat" /> <GradientStop Offset = "1" Color = "BurlyWood" /> </LinearGradientBrush> </Border.Background> <Grid x:Name = "LayoutRoot"> <Button x:Name = "fullScreenButton" HorizontalAlignment = "Center" VerticalAlignment = "Center" FontSize = "30" Width = "300" Height = "100" Content = "Go Full Screen" Click = "Button_Click" /> </Grid> </Border> </UserControl>
这是一个在 C# 中启动从全屏返回到正常的代码。您可以通过处理Host.Content 对象的FullScreenChanged 事件来了解何时发生这种情况。
using System; using System.Windows; using System.Windows.Controls; namespace FullScreenExample { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); App.Current.Host.Content.FullScreenChanged += Content_FullScreenChanged; } void Content_FullScreenChanged(object sender, EventArgs e) { if (Application.Current.Host.Content.IsFullScreen) { fullScreenButton.Content = "Return to Normal"; } else { fullScreenButton.Content = "Go Full Screen"; } } private void Button_Click(object sender, RoutedEventArgs e) { var content = Application.Current.Host.Content; content.IsFullScreen = !content.IsFullScreen; } } }
编译并执行上述代码后,您将看到以下输出。
当用户单击进入全屏按钮时,它将切换到全屏模式。
请注意按钮的文字已更改。现在显示为返回正常。如果再次点击它或按Esc键,它将退出全屏模式。
Silverlight - CSS
由于Silverlight内容始终在网页内运行,因此object标签受普通CSS布局规则的约束。插件无法将首选大小推回浏览器,因此无论Silverlight内容希望多大,其大小和位置都将完全由包含它的网页决定。
默认的Silverlight项目模板在网页中放置CSS,使object标签占据整个浏览器窗口。
默认的XAML似乎具有固定大小,但如果仔细观察,您会发现模板设置了design width和design height属性。
这些属性告诉Visual Studio或Blend在设计器中用户界面应该有多大,但它们允许它在运行时调整大小。
在解决方案资源管理器中,您将看到{project name}TestPage.html文件,这是在Visual Studio中创建新的Silverlight项目时获得的默认HTML,如下所示。
此处的顶部CSS将HTML和body样式设置为100%,这可能看起来有点奇怪。
这是完整的html文件,其中包含不同的设置。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns = "http://www.w3.org/1999/xhtml" > <head> <title>FirstExample</title> <style type = "text/css"> html, body { height: 100%; overflow: auto; } body { padding: 0; margin: 0; } #silverlightControlHost { height: 100%; text-align:center; } </style> <script type = "text/javascript" src = "Silverlight.js"></script> <script type = "text/javascript"> function onSilverlightError(sender, args) { var appSource = ""; if (sender != null && sender != 0) { appSource = sender.getHost().Source; } var errorType = args.ErrorType; var iErrorCode = args.ErrorCode; if (errorType == "ImageError" || errorType == "MediaError") { return; } var errMsg = "Unhandled Error in Silverlight Application " + appSource + "\n" ; errMsg += "Code: "+ iErrorCode + " \n"; errMsg += "Category: " + errorType + " \n"; errMsg += "Message: " + args.ErrorMessage + " \n"; if (errorType == "ParserError") { errMsg += "File: " + args.xamlFile + " \n"; errMsg += "Line: " + args.lineNumber + " \n"; errMsg += "Position: " + args.charPosition + " \n"; } else if (errorType == "RuntimeError") { if (args.lineNumber != 0) { errMsg += "Line: " + args.lineNumber + " \n"; errMsg += "Position: " + args.charPosition + " \n"; } errMsg += "MethodName: " + args.methodName + " \n"; } throw new Error(errMsg); } </script> </head> <body> <form id = "form1" runat = "server" style = "height:100%"> <div id = "silverlightControlHost"> <object data = "data:application/x-silverlight-2," type = "application/xsilverlight-2" width = "100%" height = "100%"> <param name = "source" value = "ClientBin/FirstExample.xap"/> <param name = "onError" value = "onSilverlightError" /> <param name = "background" value = "white" /> <param name = "minRuntimeVersion" value = "5.0.61118.0" /> <param name = "autoUpgrade" value = "true" /> <a href = "http://go.microsoft.com/fwlink/?LinkID=149156&v=5.0.61118.0" style = "textdecoration:none"> <img src = "http://go.microsoft.com/fwlink/?LinkId=161376" alt = "Get Microsoft Silverlight" style = "border-style:none"/> </a> </object> <iframe id = "_sl_historyFrame" style = "visibility:hidden;height:0px; width:0px;border:0px"></iframe> </div> </form> </body> </html>
查看silverlightControlHost,我们需要确保它以固定高度(例如300像素)和宽度(例如400像素)开始,这与XAML中的默认设计宽度和高度相匹配。您还可以根据应用程序需求更改这些设置。
重叠内容
默认情况下,Silverlight和HTML内容无法在屏幕上共享相同的空间。如果您创建了来自两者都的内容,使其占据相同空间,则只有Silverlight内容可见。
这是因为,默认情况下,Silverlight会向浏览器请求其自己的私有窗口,并将所有内容渲染到该窗口中。它是在浏览器内的子窗口,所以看起来像是网页的一部分,但它阻止了内容重叠。
这样做的主要原因是性能。通过获得屏幕上自己的私有区域,Silverlight不必与其渲染与网页浏览器协调。
但是,有时使用重叠内容很有用。这会带来性能上的代价。您可能会发现当Silverlight和HTML在屏幕上共享空间时,动画运行不那么流畅,但额外的布局灵活性可能值得付出这个代价。要使用重叠内容,您需要启用无窗口模式。
在无窗口模式下,Silverlight插件渲染到与浏览器相同的目标窗口处理程序,从而允许内容混合。
Z索引在内容重叠时非常重要。就HTML而言,Silverlight内容是一个单独的HTML元素,因此它出现在HTML Z顺序中的一个确切位置。
这会影响鼠标处理。如果Silverlight插件位于HTML Z顺序的顶部,则其边界框内的任何鼠标活动都将传递到插件。
即使插件的某些区域是透明的,并且您可以看到后面的HTML,您也无法点击它。
但是,如果您安排某个HTML内容的Z索引位于顶部,则即使它与Silverlight内容重叠,它也将继续保持交互性。
示例
请查看下面给出的简单示例,其中我们有一个带有容器的布局,其中三个div都已安排在此容器内部重叠。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns = "http://www.w3.org/1999/xhtml" > <head> <title>HtmlOverlap</title> <style type = "text/css"> #container { position: relative; height: 300px; font-size: small; text-align:justify; } #silverlightControlHost { position: absolute; width: 400px; height: 300px; } #underSilverlight { position: absolute; left: 4px; width: 196px; } #overSilverlight { position: relative; left: 204px; width: 196px; } </style> <script type = "text/javascript" src = "Silverlight.js"></script> <script type = "text/javascript"> function onSilverlightError(sender, args) { var appSource = ""; if (sender != null && sender != 0) { appSource = sender.getHost().Source; } var errorType = args.ErrorType; var iErrorCode = args.ErrorCode; if (errorType == "ImageError" || errorType == "MediaError") { return; } var errMsg = "Unhandled Error in Silverlight Application " + appSource + "\n" ; errMsg += "Code: "+ iErrorCode + " \n"; errMsg += "Category: " + errorType + " \n"; errMsg += "Message: " + args.ErrorMessage + " \n"; if (errorType == "ParserError") { errMsg += "File: " + args.xamlFile + " \n"; errMsg += "Line: " + args.lineNumber + " \n"; errMsg += "Position: " + args.charPosition + " \n"; } else if (errorType == "RuntimeError") { if (args.lineNumber != 0) { errMsg += "Line: " + args.lineNumber + " \n"; errMsg += "Position: " + args.charPosition + " \n"; } errMsg += "MethodName: " + args.methodName + " \n"; } throw new Error(errMsg); } </script> </head> <body> <form id = "form1" runat = "server" style = "height:100%"> <div id = 'container'> <div id = 'underSilverlight'> This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. This is below. </div> <div id = "silverlightControlHost"> <object data = "data:application/x-silverlight-2," type = "application/xsilverlight-2" width = "100%" height = "100%"> <param name = "source" value = "ClientBin/HtmlOverlap.xap"/> <param name = "onError" value = "onSilverlightError" /> <param name = "background" value = "transparent" /> <param name = "windowless" value = "true" /> <param name = "minRuntimeVersion" value = "4.0.50401.0" /> <param name = "autoUpgrade" value = "true" /> <a href = "http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0" style = "text-decoration:none"> <img src = "http://go.microsoft.com/fwlink/?LinkId=161376" alt = "Get Microsoft Silverlight" style = "border-style:none"/> </a> </object> <iframe id = "_sl_historyFrame" style = "visibility:hidden; height:0px; width:0px; border:0px"> </iframe> </div> <div id = 'overSilverlight'> This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. This is on top. </div> </div> </form> </body> </html>
此div将移到左侧,并且位于Z顺序的后面,因为它排在第一位。
然后在中间,我们有Silverlight内容,它将填充整个宽度。
然后在其顶部,右侧有一个div包含文本-这是在顶部。
下面给出的是XAML文件,其中添加了一个矩形并设置了一些属性。
<UserControl x:Class = "HtmlOverlap.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot"> <Rectangle Margin = "0,120" Fill = "Aquamarine" /> </Grid> </UserControl>
运行此应用程序时,您将看到两列,一列在左侧显示“下方”,另一列在右侧显示“上方”。Silverlight插件位于这两者的同一区域,并且在Z顺序中,Silverlight内容在这两者之间。
您可以看到此处的半透明绿色填充稍微着色了左侧的文本,因为它位于该文本的顶部,但它没有着色右侧的文本,因为它位于该文本的后面。
您可以选择右侧的文本。如果尝试使用左侧的此文本,则不会发生任何事情,这是因为就浏览器而言,此处的整个空间都被Silverlight控件占用。由于它位于Z顺序中文本的上面,因此Silverlight控件负责处理输入。
Silverlight - 控件
所有控件都具有一定的交互行为,例如,鼠标悬停在按钮上时按钮亮起以及按下时按钮按下、列表框的滚动和选择行为。在所有情况下,控件都超出了简单的可见性。它可能比看起来更复杂。这些控件是父控件和代码的组合。Silverlight允许开发人员轻松构建和创建视觉丰富的基于UI的应用程序。控件使Silverlight与其他元素区分开来。
一些重要的特性是:
其他UI框架中的经典UI元素或控件在Silverlight应用程序中也得到了增强。
几乎所有标准的Silverlight控件都可以在工具箱中找到,工具箱是System.Windows.Controls的一部分。
这些控件也可以在XAML标记语言中创建。
Silverlight控件的完整继承层次结构如下所示:
Silverlight - 按钮
Button类表示最基本的按钮控件类型。Silverlight识别三种类型的按钮控件:熟悉的Button、CheckBox和RadioButton。所有这些控件都是从ButtonBase派生的内容控件。Button类的层次继承如下所示:
下面列出了按钮最常用的属性。
序号 | 属性和描述 |
---|---|
1 | Background 获取或设置一个画刷,该画刷提供控件的背景。(从Control继承) |
2 | BorderBrush 获取或设置一个画刷,该画刷描述控件的边框填充。(从Control继承) |
3 | BorderThickness 获取或设置控件的边框粗细。(从Control继承) |
4 | Content 获取或设置ContentControl的内容。(从ContentControl继承) |
5 | ClickMode 获取或设置一个值,该值指示Click事件何时发生,以设备行为表示。(从ButtonBase继承) |
6 | ContentTemplate 获取或设置用于显示ContentControl内容的数据模板。(从ContentControl继承) |
7 | FontFamily 获取或设置用于在控件中显示文本的字体。(从Control继承) |
8 | FontSize 获取或设置此控件中文本的大小。(从Control继承) |
9 | FontStyle 获取或设置呈现文本的样式。(从Control继承) |
10 | FontWeight 获取或设置指定字体的粗细。(从Control继承) |
11 | Foreground 获取或设置一个画刷,该画刷描述前景色。(从Control继承) |
12 | Height 获取或设置FrameworkElement的建议高度。(从FrameworkElement继承) |
13 | HorizontalAlignment 获取或设置应用于FrameworkElement的水平对齐特性,当它在布局父级(如面板或项控件)中组合时。(从FrameworkElement继承) |
14 | IsEnabled 获取或设置一个值,指示用户是否可以与控件交互。(从Control继承) |
15 | IsPressed 获取一个值,指示ButtonBase当前是否处于按下状态。(从ButtonBase继承) |
16 | Margin 获取或设置FrameworkElement的外边距。(从FrameworkElement继承) |
17 | Name 获取或设置对象的标识名称。当XAML处理器从XAML标记创建对象树时,运行时代码可以通过此名称引用XAML声明的对象。(从FrameworkElement继承) |
18 | Opacity 获取或设置对象的透明度。(从UIElement继承) |
19 | Resources 获取本地定义的资源字典。在XAML中,您可以将资源项作为frameworkElement.Resources属性元素的子对象元素建立,通过XAML隐式集合语法。(从FrameworkElement继承) |
20 | Style 获取或设置一个实例Style,该Style在布局和渲染期间应用于此对象。(从FrameworkElement继承) |
21 | Template 获取或设置控件模板。控件模板定义了控件在UI中的视觉外观,并在XAML标记中定义。(从Control继承) |
22 | VerticalAlignment 获取或设置应用于FrameworkElement的垂直对齐特性,当它在父对象(如面板或项控件)中组合时。(从FrameworkElement继承) |
23 | Visibility 获取或设置UIElement的可见性。不可见的UIElement不会呈现,也不会将其所需的大小传达给布局。(从UIElement继承) |
24 | Width 获取或设置FrameworkElement的宽度。(从FrameworkElement继承) |
下面列出了按钮常用的方法。
序号 | 方法及描述 |
---|---|
1 | ClearValue 清除依赖属性的本地值。(从DependencyObject继承) |
2 | FindName 检索具有指定标识符名称的对象。(从FrameworkElement继承) |
3 | OnApplyTemplate 每当应用程序代码或内部进程(例如重建布局传递)调用ApplyTemplate时都会调用。简单来说,这意味着该方法在UI元素在应用程序中显示之前被调用。重写此方法以影响类的默认模板后逻辑。(从FrameworkElement继承) |
4 | OnContentChanged 当Content属性的值更改时调用。(从ContentControl继承) |
5 | OnDragEnter 在DragEnter事件发生之前调用。(从Control继承) |
6 | OnDragLeave 在DragLeave事件发生之前调用。(从Control继承) |
7 | OnDragOver 在DragOver事件发生之前调用。(从Control继承) |
8 | OnDrop 在Drop事件发生之前调用。(从Control继承) |
9 | OnGotFocus 在GotFocus事件发生之前调用。(从Control继承) |
10 | OnKeyDown 在KeyDown事件发生之前调用。(从Control继承) |
11 | OnKeyUp 在KeyUp事件发生之前调用。(从Control继承) |
12 | OnLostFocus 在LostFocus事件发生之前调用。(从Control继承) |
13 | SetBinding 使用提供的绑定对象将绑定附加到FrameworkElement。(从FrameworkElement继承) |
下面列出了按钮常用的事件。
序号 | 事件及说明 |
---|---|
1 | Click 当点击按钮控件时发生。(从ButtonBase继承) |
2 | DataContextChanged 当FrameworkElement.DataContext属性的值更改时发生。(从FrameworkElement继承) |
3 | DragEnter 当输入系统报告以该元素作为目标的底层拖动事件时发生。(从UIElement继承) |
4 | DragLeave 当输入系统报告以该元素为原点的底层拖动事件时发生。(继承自 UIElement) |
5 | DragOver 当输入系统报告以该元素为潜在放置目标的底层拖动事件时发生。(继承自 UIElement) |
6 | DragStarting 当拖动操作开始时发生。(继承自 UIElement) |
7 | GotFocus 当 UIElement 获得焦点时发生。(继承自 UIElement) |
8 | Holding 当在此元素的命中测试区域上发生其他未处理的按住交互时发生。(继承自 UIElement) |
9 | IsEnabledChanged 当 IsEnabled 属性更改时发生。(继承自 Control) |
10 | KeyDown 当 UIElement 具有焦点时按下键盘键时发生。(继承自 UIElement) |
11 | KeyUp 当 UIElement 具有焦点时释放键盘键时发生。(继承自 UIElement) |
12 | LostFocus 当 UIElement 失去焦点时发生。(继承自 UIElement) |
13 | SizeChanged 当 FrameworkElement 上的 ActualHeight 或 ActualWidth 属性的值发生更改时发生。(继承自 FrameworkElement) |
序号 | 按钮和说明 |
---|---|
1 | HyperlinkButton
HyperlinkButton 不会绘制标准按钮背景。相反,它只是呈现您提供的內容。 |
2 | ToggleButton 和 RepeatButton
RepeatButton 控件持续触发 Click 事件,只要按钮被按下。ToggleButton 控件表示具有两种状态(已点击或未点击)的按钮。 |
3 | CheckBox
用户可以选择(选中)或取消选择(取消选中)的控件。它提供用户可以选择的一系列选项,例如应用于应用程序的一系列设置。 |
4 | RadioButton
RadioButton 是一个按钮,允许用户从一组选项中选择单个选项。 |
Silverlight - 内容模型
这些按钮为模型内容提供了一种内容形式。模型在控件中大量出现。这个想法很简单。它将接受任何内容,而不仅仅是文本。如果您想创建一个真正奇特的按钮,您甚至可以将其他内容控件(例如文本框和按钮)放在里面(并在这些控件中嵌套更多元素)。这种界面不太可能有什么意义,但它是可能的。
让我们来看一个简单的示例,其中按钮内包含其他内容控件。
<UserControl x:Class = "ContentModel.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <Button Margin = "3" Height = "70" Width = "215"> <Grid Margin = "5"> <Polygon Points = "100,25 125,0 200,25 125,50" Fill = "LightSteelBlue" /> <Polygon Points = "100,25 75,0 0,25 75,50" Fill = "LightGray"/> </Grid> </Button> </Grid> </UserControl>
编译并执行上述代码后,您将看到以下按钮。
RangeControl
滚动条和滑块控件密切相关。它们都允许用户从特定范围内选择输入值。通常,这些控件表示不同的含义。滚动条通常用于设置滚动区域中的位置,而滑块用于指定某个值或设置。这些仅仅是约定;控件具有类似的行为和 API。
范围控件易于使用。您指定最小值和最大值以指示您希望滑块表示的值范围。Value 属性将随着用户拖动的变化而变化。
Slider 类的层次继承如下:
以下是 Slider 的常用属性。
序号 | 属性和描述 |
---|---|
1 | Header 获取或设置控件标题的内容。 |
2 | HeaderProperty 标识 Header 依赖属性。 |
3 | HeaderTemplate 获取或设置用于显示控件标题内容的 DataTemplate。 |
4 | HeaderTemplateProperty 标识 HeaderTemplate 依赖属性。 |
5 | IntermediateValue 获取或设置用户与滑块交互期间的值,在该值捕捉到刻度或步进值之前。SnapsTo 属性指定滑块的值。 |
6 | IntermediateValueProperty 标识 IntermediateValue 依赖属性。 |
7 | IsDirectionReversed 获取或设置一个值,该值指示值的增加方向。 |
8 | IsDirectionReversedProperty 标识 IsDirectionReversed 依赖属性。 |
9 | IsThumbToolTipEnabled 获取或设置一个值,该值确定是否在 Slider 的 Thumb 组件的工具提示中显示滑块值。 |
10 | IsThumbToolTipEnabledProperty 标识 IsThumbToolTipEnabled 依赖属性。 |
11 | Orientation 获取或设置 Slider 的方向。 |
12 | OrientationProperty 标识 Orientation 依赖属性。 |
13 | StepFrequency 获取或设置应为其创建步进的值范围的一部分。 |
14 | StepFrequencyProperty 标识 StepFrequency 依赖属性。 |
15 | ThumbToolTipValueConverter 获取或设置将 Slider 的范围值转换为工具提示内容的转换器逻辑。 |
16 | ThumbToolTipValueConverterProperty 标识 ThumbToolTipValueConverter 依赖属性。 |
17 | TickFrequency 获取或设置应为其创建刻度的值范围的增量。 |
18 | TickFrequencyProperty 标识 TickFrequency 依赖属性。 |
19 | TickPlacement 获取或设置一个值,该值指示相对于轨道绘制刻度标记的位置。 |
20 | TickPlacementProperty 标识 TickPlacement 依赖属性。 |
以下是 Slider 类中常用的事件。
序号 | 事件及说明 |
---|---|
1 | ManipulationCompleted 当对 UIElement 的操作完成时发生。(继承自 UIElement) |
2 | ManipulationDelta 当输入设备在操作期间更改位置时发生。(继承自 UIElement) |
3 | ManipulationInertiaStarting 当输入设备在操作期间与 UIElement 对象失去接触并开始惯性时发生。(继承自 UIElement) |
4 | ManipulationStarted 当输入设备开始对 UIElement 进行操作时发生。(继承自 UIElement) |
5 | ManipulationStarting 当第一次创建操作处理器时发生。(继承自 UIElement) |
6 | ValueChanged 当范围值更改时发生。(继承自 RangeBase) |
以下是 Slider 类中常用的方法。
序号 | 方法及描述 |
---|---|
1 | OnManipulationCompleted 在 ManipulationCompleted 事件发生之前调用。(继承自 Control) |
2 | OnManipulationDelta 在 ManipulationDelta 事件发生之前调用。(继承自 Control) |
3 | OnManipulationInertiaStarting 在 ManipulationInertiaStarting 事件发生之前调用。(继承自 Control) |
4 | OnManipulationStarted 在 ManipulationStarted 事件发生之前调用。(继承自 Control) |
5 | OnManipulationStarting 在 ManipulationStarting 事件发生之前调用。(继承自 Control) |
6 | OnMaximumChanged 当 Maximum 属性更改时调用。(继承自 RangeBase) |
7 | OnMinimumChanged 当 Minimum 属性更改时调用。(继承自 RangeBase) |
8 | OnValueChanged 触发 ValueChanged 路由事件。(继承自 RangeBase) |
9 | SetBinding 使用提供的绑定对象将绑定附加到FrameworkElement。(从FrameworkElement继承) |
10 | SetValue 设置 DependencyObject 上依赖属性的本地值。(继承自 DependencyObject) |
示例
让我们来看一个简单的示例,其中添加了一个滑块和一个椭圆,并且滑块控制椭圆的宽度。
<UserControl x:Class = "SliderExample.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = " http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignWidth = "640" d:DesignHeight = "480"> <Grid x:Name = "LayoutRoot"> <Grid.RowDefinitions> <RowDefinition Height = "Auto" /> <RowDefinition /> </Grid.RowDefinitions> <Slider Minimum = "1" Maximum = "400" Value = "1" ValueChanged = "Slider_ValueChanged" /> <Ellipse Grid.Row = "1" Fill = "Aqua" Width = "1" x:Name = "myEllipse" /> </Grid> </UserControl>
以下是 C# 中的值更改事件实现。
using System.Windows; using System.Windows.Controls; namespace SliderExample { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void Slider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) { if (myEllipse != null) { myEllipse.Width = e.NewValue; } } } }
编译并执行上述代码后,您将看到以下输出。如您所见,当您将滑块从左向右移动时,椭圆的宽度会增加。
Silverlight - ListBox
Listbox 是一种控件,它为用户提供项目列表以供选择。用户可以一次从预定义的项目列表中选择一个或多个项目。在ListBox 中,多个选项始终对用户可见,无需任何用户交互。
Listbox 显示一个可滚动的项目列表。如果用户选择一个项目,则所选项目的显示外观将发生变化以指示选择。它支持更广泛的内容模型和按钮。按钮和列表框之间的主要区别在于,按钮包含单个内容,而列表框允许列表中的每个项目。
ListBox 类的层次继承如下:
以下是 ListBox 类中常用的属性。
序号 | 属性和描述 |
---|---|
1 | Background 获取或设置一个画刷,该画刷提供控件的背景。(从Control继承) |
2 | BorderThickness 获取或设置控件的边框粗细。(从Control继承) |
3 | FontFamily 获取或设置用于在控件中显示文本的字体。(从Control继承) |
4 | FontSize 获取或设置此控件中文本的大小。(从Control继承) |
5 | FontStyle 获取或设置呈现文本的样式。(从Control继承) |
6 | FontWeight 获取或设置指定字体的粗细。(从Control继承) |
7 | Foreground 获取或设置一个画刷,该画刷描述前景色。(从Control继承) |
8 | GroupStyle 获取 GroupStyle 对象的集合,这些对象定义每一级组的外观。(继承自 ItemsControl) |
9 | Height 获取或设置FrameworkElement的建议高度。(从FrameworkElement继承) |
10 | HorizontalAlignment 获取或设置应用于FrameworkElement的水平对齐特性,当它在布局父级(如面板或项控件)中组合时。(从FrameworkElement继承) |
11 | IsEnabled 获取或设置一个值,指示用户是否可以与控件交互。(从Control继承) |
12 | Item 获取用于生成控件内容的集合。(继承自 ItemsControl) |
13 | ItemsSource 获取或设置用于生成 ItemsControl 内容的对象源。(继承自 ItemsControl) |
14 | Margin 获取或设置FrameworkElement的外边距。(从FrameworkElement继承) |
15 | Name 获取或设置对象的标识名称。当 XAML 处理器从 XAML 标记创建对象树时,运行时代码可以通过此名称引用 XAML 声明的对象。(继承自 FrameworkElement) |
16 | Opacity 获取或设置对象的透明度。(从UIElement继承) |
17 | SelectedIndex 获取或设置所选项目的索引。(继承自 Selector) |
18 | SelectedItem 获取或设置所选项目。(继承自 Selector) |
19 | SelectedValue 获取或设置所选项目的值,通过使用 SelectedValuePath 获取。(继承自 Selector) |
20 | Style 获取或设置一个实例Style,该Style在布局和渲染期间应用于此对象。(从FrameworkElement继承) |
21 | VerticalAlignment 获取或设置应用于FrameworkElement的垂直对齐特性,当它在父对象(如面板或项控件)中组合时。(从FrameworkElement继承) |
22 | Width 获取或设置FrameworkElement的宽度。(从FrameworkElement继承) |
以下是 ListBox 的常用事件。
序号 | 事件及说明 |
---|---|
1 | DragEnter 当输入系统报告以该元素作为目标的底层拖动事件时发生。(从UIElement继承) |
2 | DragLeave 当输入系统报告以该元素为原点的底层拖动事件时发生。(继承自 UIElement) |
3 | DragOver 当输入系统报告以该元素为潜在放置目标的底层拖动事件时发生。(继承自 UIElement) |
4 | DragStarting 当拖动操作开始时发生。(继承自 UIElement) |
5 | Drop 当输入系统报告以该元素为放置目标的底层放置事件时发生。(继承自 UIElement) |
6 | DropCompleted 当拖放操作结束时发生。(继承自 UIElement) |
7 | GotFocus 当 UIElement 获得焦点时发生。(继承自 UIElement) |
8 | IsEnabledChanged 当 IsEnabled 属性更改时发生。(继承自 Control) |
9 | KeyDown 当 UIElement 具有焦点时按下键盘键时发生。(继承自 UIElement) |
10 | KeyUp 当 UIElement 具有焦点时释放键盘键时发生。(继承自 UIElement) |
11 | LostFocus 当 UIElement 失去焦点时发生。(继承自 UIElement) |
12 | SelectionChanged 当当前选定的项目更改时发生。(继承自 Selector) |
13 | SizeChanged 当 FrameworkElement 上的 ActualHeight 或 ActualWidth 属性的值发生更改时发生。(继承自 FrameworkElement) |
以下是 ListBox 的常用方法。
序号 | 方法及描述 |
---|---|
1 | Arrange 定位子对象并确定 UIElement 的大小。实现其子元素自定义布局的父对象应从其布局覆盖实现中调用此方法,以形成递归布局更新。(继承自 UIElement) |
2 | FindName 检索具有指定标识符名称的对象。(从FrameworkElement继承) |
3 | Focus 尝试将焦点设置到控件上。(继承自 Control) |
4 | GetValue 返回 DependencyObject 上依赖属性的当前有效值。(继承自 DependencyObject) |
5 | IndexFromContainer 返回具有指定生成容器的项目的索引。(继承自 ItemsControl) |
6 | OnDragEnter 在DragEnter事件发生之前调用。(从Control继承) |
7 | OnDragLeave 在DragLeave事件发生之前调用。(从Control继承) |
8 | OnDragOver 在DragOver事件发生之前调用。(从Control继承) |
9 | OnDrop 在Drop事件发生之前调用。(从Control继承) |
10 | OnKeyDown 在KeyDown事件发生之前调用。(从Control继承) |
11 | OnKeyUp 在KeyUp事件发生之前调用。(从Control继承) |
12 | OnLostFocus 在LostFocus事件发生之前调用。(从Control继承) |
13 | ReadLocalValue 返回依赖属性的本地值(如果设置了本地值)。(继承自 DependencyObject) |
14 | SetBinding 使用提供的绑定对象将绑定附加到FrameworkElement。(从FrameworkElement继承) |
15 | SetValue 设置 DependencyObject 上依赖属性的本地值。(继承自 DependencyObject) |
让我们来看一个简单的示例,其中在ListBox 中添加了不同的 UI 元素。
<UserControl x:Class = "ListBoxExample.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignWidth = "640" d:DesignHeight = "480"> <Grid x:Name = "LayoutRoot"> <ListBox x:Name = "myList"> <TextBlock Text = "First item" /> <Button Content = "Second item" /> <Path Fill = "Blue" Data = "M4,0 l-4,10 8,0z M15,0 l-4,10 8,0z M26,0 l4,10 8,0z" Margin = "10" /> <StackPanel Orientation = "Horizontal"> <Ellipse Fill = "Red" Height = "30" Width = "100" /> <TextBlock Text = "Name: " /> <TextBox Width = "200" /> </StackPanel> <TextBlock Text = "More..." /> </ListBox> </Grid> </UserControl>
以下是 C# 实现。
using System.Windows.Controls; namespace ListBoxExample { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); myList.Items.Add("String entry"); myList.Items.Add(new Button { Content = "Content entry" }); } } }
编译并执行上述代码后,您将看到一个列表框,其中包含图形文本的混合,以及一个可编辑的字段,您可以在其中键入文本。
序号 | 控件及描述 |
---|---|
1 | Calendar 和 DatePicker
日历和日期选择器表示一个控件,用户可以通过可视化日历显示来选择日期。它提供了一些基本的鼠标或键盘导航。 |
2 | 选项卡控件
一个容器,将项目放置到单独的选项卡中,并允许用户一次只查看一个选项卡。它允许用户通过点击选项卡标题从多个不同的视图中进行选择。 |
3 | 弹出窗口
此类在应用程序窗口的范围内,将内容显示在现有内容之上。它是在其他内容上临时显示。 |
4 | 工具提示
工具提示表示一个控件,它创建一个弹出窗口,用于显示 GUI 中元素的信息。Silverlight 允许您将工具提示附加到任何控件。 |
Silverlight - 模板
一个模板描述了控件的整体外观和视觉外观。每个控件都与其关联一个默认模板,该模板赋予该控件外观。
在 WPF 应用程序中,当您想要自定义控件的视觉行为和视觉外观时,可以轻松创建自己的模板。
一些重要的特性是:
所有 UI 元素都具有一定的外观和行为,例如按钮具有外观和行为。
单击事件或鼠标悬停事件是行为,它们响应单击和悬停而触发,并且按钮有一个默认外观,可以通过控件模板更改。
让我们再次看一个简单的示例,其中使用模板定义了一个按钮。
<UserControl x:Class = "ButtonTemplate.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignWidth = "640" d:DesignHeight = "480"> <Grid x:Name = "LayoutRoot" HorizontalAlignment = "Center" VerticalAlignment = "Center"> <Button Height = "100" Width = "100" Content = "Click!" HorizontalContentAlignment = "Left" Click = "button_Click"> <Button.Template> <ControlTemplate TargetType = "Button"> <Grid> <Ellipse Fill = "Gray" Stroke = "Black" StrokeThickness = "3" Margin = "-64,0,0,0" /> <ContentPresenter HorizontalAlignment = "{TemplateBinding HorizontalContentAlignment}" VerticalAlignment = "Center" Content = "{TemplateBinding Content}" /> </Grid> </ControlTemplate> </Button.Template> </Button> </Grid> </UserControl>
编译并执行上述代码后,您将看到以下输出。
连接模板
我们想要模板化的所有控件功能都使用模板绑定。某些方面稍微复杂一些。例如,无论何时您拥有某种内容模型,仅使用模板绑定是不够的,如您在按钮上看到的。我们还必须使用内容呈现器,如上例所示。
Silverlight - 可视状态
如果您的用户能够分辨出应用程序的哪个部分可能响应输入,那将是很好的。在某种程度上,可以通过使按钮看起来像按钮来做到这一点。如果某物看起来可点击,它可能就是可点击的。
但是,现代用户界面设计的惯例是,用户界面元素还应该通过在鼠标移动到它们上面时更改其外观来表示其响应意愿。
例如,内置的按钮控件在鼠标移到上面时会稍微更改其背景,以暗示它是交互式的,然后在单击时进一步更改其外观,使其看起来像被选中。几乎所有控件都需要这样做,并且设计人员需要一种方法来创建和编辑动画以使其发生。
状态和状态组
让我们看一个视觉状态在实际应用中的示例。考虑一个复选框。它可以是未选中或选中状态,如果您选择,它可以支持第三种不确定状态。对于所有三种情况,控件都需要看起来有所不同。因此,我们有三个视觉状态。
为了表明它已准备好响应用户输入,复选框在鼠标移到它上面时会稍微更改其外观,并且在鼠标保持在该位置时会进一步更改。如果复选框被禁用,则需要考虑第四种状态,它看起来是灰色的,并表示它不会响应用户输入。
因此,这里还有另外四种状态。在任何给定时间,复选框的视觉状态必须是正常、鼠标悬停、选中或禁用之一。同时,它必须是选中、未选中或不确定之一。
视觉状态管理器
由于其模板定义了控件的外观,因此模板需要定义每个视觉状态发生的情况。我们到目前为止看到的模板不包含此类信息。因此,无论控件的当前状态如何,控件的外观都保持静态。
要向模板添加视觉状态,您可以从添加属性元素开始。
对于视觉状态处理,您可以做的最简单的事情是定义在控件进入特定状态时将运行的动画。
控件在每次更改状态时都会通知视觉状态管理器类。
然后,视觉状态管理器会查看模板的这一部分,并确定要运行哪个动画。
因此,当复选框进入鼠标悬停状态时,此动画将运行,更改模板某些部分的颜色。
让我们看一个简单的示例,使用视觉状态机制为复选框创建一个自定义模板,以反映状态更改。
下面是带有视觉状态的复选框自定义模板的 XAML 代码。
<UserControl xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" x:Class = "CheckboxVisualState.Page" Width = "640" Height="480" xmlns:vsm = "clrnamespace:System.Windows;assembly = System.Windows" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d"> <UserControl.Resources> <ControlTemplate x:Key = "CheckBoxControlTemplate1" TargetType = "CheckBox"> <Grid> <vsm:VisualStateManager.VisualStateGroups> <vsm:VisualStateGroup x:Name = "FocusStates"> <vsm:VisualState x:Name = "ContentFocused"/> <vsm:VisualState x:Name = "Focused"/> <vsm:VisualState x:Name = "Unfocused"/> </vsm:VisualStateGroup> <vsm:VisualStateGroup x:Name = "CommonStates"> <vsm:VisualStateGroup.Transitions> <vsm:VisualTransition GeneratedDuration = "00:00:00.5000000"/> </vsm:VisualStateGroup.Transitions> <vsm:VisualState x:Name = "MouseOver"> <Storyboard> <ColorAnimationUsingKeyFrames BeginTime = "00:00:00" Duration = "00:00:00.0010000" Storyboard.TargetName = "background" Storyboard.TargetProperty = "(Shape.Fill). (SolidColorBrush.Color)"> <SplineColorKeyFrame KeyTime = "00:00:00" Value = "#FFFF0000"/> </ColorAnimationUsingKeyFrames> </Storyboard> </vsm:VisualState> <vsm:VisualState x:Name = "Pressed"> <Storyboard> <ColorAnimationUsingKeyFrames BeginTime = "00:00:00" Duration = "00:00:00.0010000" Storyboard.TargetName = "background" Storyboard.TargetProperty = "(Shape.Fill). (SolidColorBrush.Color)"> <SplineColorKeyFrame KeyTime = "00:00:00" Value = "#FFCEFF00"/> </ColorAnimationUsingKeyFrames> </Storyboard> </vsm:VisualState> <vsm:VisualState x:Name = "Disabled"/> <vsm:VisualState x:Name = "Normal"/> </vsm:VisualStateGroup> <vsm:VisualStateGroup x:Name = "CheckStates"> <vsm:VisualStateGroup.Transitions> <vsm:VisualTransition GeneratedDuration = "00:00:00.5000000"/> </vsm:VisualStateGroup.Transitions> <vsm:VisualState x:Name = "Checked"> <Storyboard> <DoubleAnimationUsingKeyFrames BeginTime = "00:00:00" Duration = "00:00:00.0010000" Storyboard.TargetName = "checkPath" Storyboard.TargetProperty = "(UIElement.Opacity)"> <SplineDoubleKeyFrame KeyTime = "00:00:00" Value = "1"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </vsm:VisualState> <vsm:VisualState x:Name = "Unchecked"/> <vsm:VisualState x:Name = "Indeterminate"/> </vsm:VisualStateGroup> </vsm:VisualStateManager.VisualStateGroups> <Grid.ColumnDefinitions> <ColumnDefinition Width = "Auto"/> <ColumnDefinition Width = "3.61782296696066"/> <ColumnDefinition Width = "Auto"/> </Grid.ColumnDefinitions> <Canvas Height = "50" HorizontalAlignment = "Left" VerticalAlignment = "Top" Width = "50"> <Rectangle Height = "33.746" x:Name = "background" Width = "33.746" Canvas.Left = "8.452" Canvas.Top = "7.88" Fill = "#FFFFFFFF" Stroke = "#FF000000" RadiusX = "5.507" RadiusY = "5.507"/> <Path Height = "40.25" x:Name = "checkPath" Width = "39.75" Opacity = "0" Canvas.Left = "5.959" Canvas.Top = "7.903" Stretch = "Fill" Stroke = "#FF1F9300" StrokeThickness = "3" Data = "M1.5,1.5 C15.495283,8.7014561 27.056604,18.720875 33.75,33.75 M36,3.75 C22.004717,10.951456 10.443395,20.970875 3.7499986,36"/> </Canvas> <ContentPresenter HorizontalAlignment = "Left" Margin = "{TemplateBinding Padding}" VerticalAlignment = "{TemplateBinding VerticalContentAlignment}" Grid.Column = "2" Grid.ColumnSpan = "1" d:LayoutOverrides = "Height"/> </Grid> </ControlTemplate> </UserControl.Resources> <Grid x:Name = "LayoutRoot" Background = "White" > <CheckBox HorizontalAlignment = "Left" Margin = "52.5410003662109,53.5970001220703,0,0" VerticalAlignment = "Top" Template = "{StaticResource CheckBoxControlTemplate1}" Content = "CheckBox"/> </Grid> </UserControl>
编译并执行上述代码后,您将看到以下网页,其中包含一个复选框。
当光标进入复选框区域时,它将更改状态。
单击复选框时,您将看到以下状态。
我们建议您执行上述示例以更好地理解。
Silverlight - 数据绑定
数据绑定是 Silverlight 应用程序中的一种机制,它为使用部分类的 Windows 运行时应用程序提供了一种简单易行的方式来显示和交互数据。在此机制中,数据的管理与数据在用户界面中显示的方式完全分离。数据绑定允许数据在 UI 元素和用户界面上的数据对象之间流动。当建立绑定并且数据或您的业务模型发生变化时,它将自动将更新反映到 UI 元素,反之亦然。也可以绑定到页面上的另一个元素,而不是绑定到标准数据源。
数据绑定分为以下两种类型:
- 单向数据绑定
- 双向数据绑定
单向数据绑定
在单向数据绑定中,数据从其源(即保存数据的对象)绑定到其目标(即显示数据的对象)。
让我们看一个简单的单向数据绑定示例。
下面是 XAML 代码,其中创建了两个标签、两个文本框和一个按钮,并设置了一些属性。
<UserControl x:Class = "DataBinding.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <Grid.RowDefinitions> <RowDefinition Height = "Auto" /> <RowDefinition Height = "Auto" /> <RowDefinition Height = "*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width = "Auto" /> <ColumnDefinition Width = "200" /> </Grid.ColumnDefinitions> <TextBlock Name = "nameLabel" Margin = "2">Name:</TextBlock> <TextBox Name = "nameText" Grid.Column = "1" Margin = "2" Text = "{Binding Name, Mode=OneWay}"/> <TextBlock Name = "ageLabel" Margin = "2" Grid.Row = "1">Age:</TextBlock> <TextBox Name = "ageText" Grid.Column = "1" Grid.Row = "1" Margin="2" Text = "{Binding Age, Mode = OneWay}"/> <StackPanel Grid.Row = "2" Grid.ColumnSpan = "2"> <Button Content = "_Show..." Click = "Button_Click" /> </StackPanel> </Grid> </UserControl>
我们观察到以下几点:
两个文本框的文本属性分别绑定到“Name”和“Age”,它们是Person类的类变量,如下所示。
在Person类中,我们只有两个变量Name和Age,并且其对象在MainPage类中初始化。
在 XAML 代码中,我们绑定到属性Name和Age,但我们没有选择哪个属性属于该对象。
一种简单的方法是在MainPage构造函数的 C# 代码中将对象分配给DataContext,我们在其中绑定属性,如下所示。
using System.Windows; using System.Windows.Controls; namespace DataBinding { public partial class MainPage : UserControl { Person person = new Person { Name = "Salman", Age = 26 }; public MainPage() { InitializeComponent(); this.DataContext = person; } private void Button_Click(object sender, RoutedEventArgs e) { string message = person.Name + " is " + person.Age; MessageBox.Show(message); } } public class Person { private string nameValue; public string Name { get { return nameValue; } set { nameValue = value; } } private double ageValue; public double Age { get { return ageValue; } set { if (value != ageValue) { ageValue = value; } } } } }
让我们运行此应用程序,您会立即在网页中看到我们已成功绑定到该Person对象的Name和Age。
按下显示按钮时,它将在消息框中显示姓名和年龄。
让我们更改上述对话框中的Name和Age。
现在,如果您单击显示按钮,它将再次显示相同的消息。
这是因为数据绑定模式在 XAML 代码中设置为单向。要显示更新的消息,您需要了解双向数据绑定。
双向数据绑定
在双向绑定中,用户能够通过用户界面修改数据,并将该数据更新到源中。如果源在用户查看视图时发生更改,则希望视图更新。
让我们看同一个示例,但仅将 XAML 代码中的绑定模式从单向更改为双向,如下所示。
<UserControl x:Class = "DataBinding.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <Grid.RowDefinitions> <RowDefinition Height = "Auto" /> <RowDefinition Height = "Auto" /> <RowDefinition Height = "*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width = "Auto" /> <ColumnDefinition Width = "200" /> </Grid.ColumnDefinitions> <TextBlock Name = "nameLabel" Margin = "2">_Name:</TextBlock> <TextBox Name = "nameText" Grid.Column = "1" Margin = "2" Text = "{Binding Name, Mode=TwoWay}"/> <TextBlock Name = "ageLabel" Margin = "2" Grid.Row = "1">_Age:</TextBlock> <TextBox Name = "ageText" Grid.Column = "1" Grid.Row = "1" Margin = "2" Text = "{Binding Age, Mode = TwoWay}"/> <StackPanel Grid.Row = "2" Grid.ColumnSpan = "2"> <Button Content = "_Show..." Click = "Button_Click" /> </StackPanel> </Grid> </UserControl>
让我们再次运行此应用程序,您会看到相同的输出。
让我们更改上述对话框中的Name和Age。
现在,如果您单击显示按钮,它将显示更新的消息。
Silverlight - 浏览器集成
在本章中,我们将了解 Silverlight 应用程序如何使用浏览器集成支持与网页一起工作。
我们可以通过以下两种方式探索 Silverlight 与浏览器的集成:
在浏览器中运行的 JavaScript 代码可以访问 Silverlight 应用程序中的功能。
Silverlight 能够为对象提供 JavaScript 包装器。由于 Silverlight 为 JavaScript 对象提供了.NET包装器,因此在 Silverlight 插件内部运行的.NET代码可以访问 HTML DOM 和其他浏览器脚本功能。
我们将了解基于浏览器的软件应用程序如何持久地将信息存储在客户端。
Silverlight 和 HTML
就 HTML 世界而言,Silverlight 内容只是一个单个元素。这对布局来说是正确的。整个 Silverlight 插件及其所有内容看起来都像一个对象元素。
您必须牢记:
Silverlight 不是 HTML 的替代品,它是为了补充 HTML 而设计的。因此,能够访问 DOM 中的另一个元素非常重要。
它使您能够在适当的地方使用 Silverlight。
在一个主要使用 HTML 的页面上,Silverlight 与浏览器世界的集成不仅仅是作为 DOM 元素存在,还受普通 HTML 布局的约束。
访问 DOM
Silverlight 内容必须能够完全参与网页。因此,它应该能够访问 HTML DOM。Silverlight 提供了包装浏览器脚本对象作为 Dot Net 对象的桥接对象,即系统中的Script 对象类。浏览器命名空间提供了一些方法,允许您读取和写入属性并调用浏览器脚本对象上的函数。
首先,您需要一种获取 Script 对象的方法。Silverlight 提供了一个 HTML 页面类,使您可以访问各种页面功能,例如 Script 对象。
让我们看一个简单的示例,其中我们有一个简单的脚本,它创建一个具有几个属性的对象。其中一些只是值,而另一些是函数。
<script type = "text/javascript"> myJsObject = { answer: 42, message: "Hello, world", modifyHeading: function(title) { document.getElementById('heading').innerHTML = title; }, performReallyComplexCalculation: function(x, y) { return x + y; } }; </script>
下面是 XAML 代码,其中添加了一个按钮。
<UserControl x:Class = "DomAccess.Page" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" Width = "400" Height = "300"> <Grid x:Name = "LayoutRoot" Background = "White"> <Button x:Name = "useDomButton" Content = "Use DOM" Width = "75" Height = "30" Click = "useDomButton_Click" /> </Grid> </UserControl>
这是按钮单击实现,其中调用了在 HTML 文件中创建的脚本。
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.Windows.Browser; using System.Diagnostics; namespace DomAccess { public partial class Page : UserControl { public Page() { InitializeComponent(); } private void useDomButton_Click(object sender, RoutedEventArgs e) { ScriptObject myJsObject = HtmlPage.Window.GetProperty("myJsObject") as ScriptObject; string[] propertyNames = { "answer", "message", "modifyHeading", "performReallyComplexCalculation" }; foreach (string propertyName in propertyNames) { object value = myJsObject.GetProperty(propertyName); Debug.WriteLine("{0}: {1} ({2})", propertyName, value, value.GetType()); } object result = myJsObject.Invoke("performReallyComplexCalculation", 11, 31); HtmlElement h1 = HtmlPage.Document.GetElementById("heading"); h1.SetProperty("innerHTML", "Text from C# (without JavaScript's help)"); h1.SetStyleAttribute("height", "200px"); } } }
下面是完整的 HTML 文件。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns = "http://www.w3.org/1999/xhtml" > <!-- saved from url = (0014)about:internet --> <head> <title>DomAccess</title> <script type = "text/javascript"> myJsObject = { answer: 42, message: "Hello, world", modifyHeading: function(title) { document.getElementById('heading').innerHTML = title; }, performReallyComplexCalculation: function(x, y) { return x + y; } }; </script> <style type = "text/css"> html, body { height: 100%; overflow: auto; } body { padding: 0; margin: 0; } #silverlightControlHost { height: 100%; } </style> <script type = "text/javascript" src = "Silverlight.js"></script> <script type = "text/javascript"> function onSilverlightError(sender, args) { var appSource = ""; if (sender != null && sender != 0) { appSource = sender.getHost().Source; } var errorType = args.ErrorType; var iErrorCode = args.ErrorCode; var errMsg = "Unhandled Error in Silverlight 2 Application " + appSource + "\n" ; errMsg += "Code: "+ iErrorCode + " \n"; errMsg += "Category: " + errorType + " \n"; errMsg += "Message: " + args.ErrorMessage + " \n"; if (errorType == "ParserError") { errMsg += "File: " + args.xamlFile + " \n"; errMsg += "Line: " + args.lineNumber + " \n"; errMsg += "Position: " + args.charPosition + " \n"; } else if (errorType == "RuntimeError") { if (args.lineNumber != 0) { errMsg += "Line: " + args.lineNumber + " \n"; errMsg += "Position: " + args.charPosition + " \n"; } errMsg += "MethodName: " + args.methodName + " \n"; } throw new Error(errMsg); } </script> </head> <body> <!-- Runtime errors from Silverlight will be displayed here. This will contain debugging information and should be removed or hidden when debugging is completed --> <div id = 'errorLocation' style = "font-size: small;color: Gray;"></div> <h1 id = 'heading'></h1> <div id = "silverlightControlHost"> <object data = "data:application/x-silverlight-2," type = "application/x-silverlight-2" width = "100%" height = "100%"> <param name = "source" value = "ClientBin/DomAccess.xap"/> <param name = "onerror" value = "onSilverlightError" /> <param name = "background" value = "white" /> <param name = "minRuntimeVersion" value = "2.0.30923.0" /> <param name = "autoUpgrade" value = "true" /> <a href = "http://go.microsoft.com/fwlink/?LinkID=124807" style = "text-decoration: none;"> <img src = "http://go.microsoft.com/fwlink/?LinkId=108181" alt = "Get Microsoft Silverlight" style = "border-style: none"/> </a> </object> <iframe style = 'visibility:hidden;height:0;width:0;border:0px'></iframe> </div> </body> </html>
编译并执行上述代码后,您将在输出窗口中看到所有值,这些值是从 HTML 文件中获取的。
Silverlight - 浏览器外应用程序
现在我们将探讨 Silverlight 对应用程序的支持,这些应用程序可以安装在最终用户的计算机上,并在 Web 浏览器外部运行,就像普通的 Windows 应用程序一样。您可能希望应用程序能够在浏览器外部运行,主要有三个原因:
- 交互性
- 离线
- 提升的信任级别
交互性
它可以实现更好的交互设计。Web 的导航模型并不特别适合某些应用程序。例如,地址栏和后退按钮可能是浪费空间,并且毫无用处。
Silverlight 在此处的意义如下:
Web 应用程序可以使用客户端技术(例如 Silverlight、Flash 或 AJAX)为单个页面提供持续更新,这可能会消除导航到其他页面的需要。
在某些应用程序中,用户可能会花费数分钟甚至数小时来使用浏览器认为是单个页面的内容。
对于此类应用程序,后退按钮最终可能会产生相当意外的效果,即退出应用程序,因为它会将您带回到进入应用程序之前所在的页面。
明显地,非 Web 类应用程序通常最好在浏览器外部运行,因为这样可以去除浏览器 Chrome。通常,可用性不是在浏览器外部运行的唯一原因。
离线
使用此功能的另一个原因是启用离线执行。当 Silverlight 应用程序安装用于浏览器外部操作时,它会被复制到本地计算机上的每个用户存储库中,并可以通过通常的操作系统机制(例如 Windows 上的“开始”菜单)启动应用程序。
即使用户没有互联网连接,该应用程序也将可用。
显然,这仅对不完全依赖服务器端信息的应用程序才有帮助。
例如,包裹递送服务的自动跟踪应用程序在没有网络连接的情况下用处不大。
对于某些应用程序,能够在偶尔的连接故障期间继续工作非常有用。
提升的信任级别
Silverlight 的 4 版增加了对受信任应用程序的支持。Silverlight 的安全沙箱通常会阻止某些特权操作,例如访问用户的文件。
但是,浏览器外部的应用程序可能会请求提升权限。如果用户授予该请求,则该应用程序能够执行更多任何普通 Windows 应用程序能够执行的工作,例如利用 COM 自动化或自定义窗口边框。
在浏览器内运行的应用程序永远不会被信任,因此,如果您想使用这些功能,则必须编写浏览器外部的应用程序。
启用 OOB
我们如何编写浏览器外部的应用程序?这非常容易。我们只需要更改 Silverlight 项目属性中的单个设置,它会向AppManifest.xaml添加合适的设置。
让我们看看它是如何工作的。
当您的清单指示支持浏览器外部执行时,这不会立即生效。应用程序将照常在浏览器中运行。
但是,如果用户右键单击,标准 Silverlight上下文菜单将提供一个额外的项目来将应用程序安装到计算机上。
如果用户选择该项目,将出现一个对话框,要求确认。它还会询问应用程序是否应从“开始”菜单、桌面或两者都访问。
您不必依赖上下文菜单。您还可以提供一个按钮,用户可以单击该按钮来安装应用程序,因为存在一个 API,您可以调用它来启动安装。
当您以编程方式启动安装程序时,用户仍然会看到对话框。未经用户同意,您无法安装应用程序。
Silverlight 应用程序
这是一个非常简单的 Silverlight 应用程序。以下是其 XAML 代码。
<UserControl x:Class = "SimpleOob.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <Border BorderBrush = "Blue" BorderThickness = "4" CornerRadius = "20" > <Border.Background> <LinearGradientBrush StartPoint = "0,0" EndPoint = "0,1"> <GradientStop Offset = "0.0" Color = "White" /> <GradientStop Offset = "0.15" Color = "#cef" /> <GradientStop Offset = "1.0" Color = "White" /> </LinearGradientBrush> </Border.Background> <TextBlock HorizontalAlignment = "Center" VerticalAlignment = "Center" Text = "Silverlight Application" TextOptions.TextHintingMode = "Animated" TextAlignment = "Center" TextWrapping = "Wrap" FontSize = "72" FontFamily = "Trebuchet MS" > <TextBlock.Effect> <DropShadowEffect Color = "#888" /> </TextBlock.Effect> </TextBlock> </Border> </Grid> </UserControl>
步骤 1 - 要启用浏览器外部执行,请转到项目的属性,然后单击 Silverlight 选项卡。我们只需选中启用在浏览器外部运行应用程序复选框。
如果您运行此应用程序,您会注意到根本不会出现 Web 浏览器。
实际上,Visual Studio 已代表您做出了决定。当您启用浏览器外部执行时,它不公平地更改了您的调试设置。
步骤 2 - 因此,在此处的解决方案资源管理器中,请注意 Silverlight 项目现在以粗体显示,表示它是启动项目。
以前情况并非如此。它一直是 Web 项目。现在,我们不希望这样,因为我们想展示该复选框如何为最终用户更改内容。
步骤 3 - 我们将 Web 项目设置回启动项目。
步骤 4 - 再次运行应用程序,您会看到应用程序现在已回到浏览器中。
步骤 5 - 右键单击网页。您会在上下文菜单中看到通常的 Silverlight 条目,以及一个额外的安装项目。
步骤 6 - 选择第二个选项时,将出现“安装应用程序”对话框,如下所示。
请注意,它显示了网站的根 URL,应用程序来自该网站。我们使用 Visual Studio 提供的本地调试 Web 服务器,这就是它显示 localhost 的原因。
步骤 7 - 单击确定,应用程序将在独立于浏览器的自己的窗口中运行。
您可能会自然地认为此窗口以某种方式由浏览器拥有或与其连接,但事实并非如此。您可以关闭浏览器,而此窗口将保留。更重要的是,您可以关闭此窗口,然后在根本不使用浏览器的情况下重新运行应用程序。
步骤 8 - 如果您在开始菜单中打开搜索对话框并开始键入应用程序名称,它将像任何普通的 Windows 应用程序一样显示。
步骤 9 - 您可以在浏览器完全不可见的情况下运行它。
卸载应用程序
应用程序上的默认上下文菜单提供了一种简单的方法来执行此操作。用户可以合理地期望以与卸载任何其他应用程序相同的方式卸载此应用程序。
您也可以通过右键单击网页并选择删除此应用程序…来删除。
OOB 设置
尽管我们只需要更改一个设置即可启用浏览器外部操作,但在实践中,您通常希望执行的操作不止这些。AppManifest.xaml文件可以包含多个与浏览器外部操作相关的设置,我们通常通过 Visual Studio 进行配置。
您可能已经注意到,当您选中启用在浏览器外部运行的复选框时,Visual Studio 启用了名为浏览器外部设置的按钮。
让我们通过单击该按钮来查看它。它将生成以下对话框。
我们可以配置的第一件事是显示为窗口标题的文本。
我们还可以选择修复窗口尺寸和位置,但现在我们将保留为自动。
此快捷方式名称显示在开始菜单中,以及应用程序安装后的桌面链接。
它也是上下文菜单和安装应用程序对话框中显示的文本。
此应用程序描述显示在将鼠标悬停在快捷方式上时的工具提示中。
我们可以提供各种尺寸的图标。这些必须内置到您的项目中。
应用程序、资源和部署
在本章中,我们将了解围绕创建和部署应用程序及其所需资源的常见问题。
加载插件
运行 Silverlight 应用程序的最低要求是包含用于加载 Silverlight 插件的对象标记的主机网页,以及编译后的 Silverlight 内容本身。
如您所见,我们在对象标记中使用了param标记来指向内容。
HTML <Object> 标记
我们可以传递其他参数来控制功能,例如在下载内容时显示的用户界面、在发生错误时运行的 JavaScript 代码以及在未安装 Silverlight 时显示的回退内容。
<Object> 在 HTML 中
这是一个加载某些 Silverlight 内容的示例对象标记。您之前已经见过它,但我们将更详细地了解一些内容,首先从对象标记本身的属性开始。
Type 属性
type 属性包含一个 MIME 类型,将其标识为 Silverlight 元素。这是浏览器了解我们使用哪种嵌入内容的方式。对象标记非常灵活。它不仅用于插件。您还可以使用它来托管嵌入图像或 HTML,以及基于插件的内容,例如 Silverlight 或 Flash。
如果安装了 Silverlight 插件,则将加载它。如果没有,则标准格式行为是浏览器呈现对象标记内的任何 HTML 内容,就好像对象和 param 标记不存在一样。
<object data = "data:application/x-silverlight-2," type = "application/x-silverlight-2" width = "100%" height = "100%"> <param name = "source" value = "ClientBin/DataBinding.xap"/> <param name = "onError" value = "onSilverlightError" /> <param name = "background" value = "white" /> <param name = "minRuntimeVersion" value = "5.0.61118.0" /> <param name = "autoUpgrade" value = "true" /> <a href = "http://go.microsoft.com/fwlink/?LinkID=149156&v=5.0.61118.0" style = "textdecoration:none"> <img src = "http://go.microsoft.com/fwlink/?LinkId=161376" alt = "Get Microsoft Silverlight" style = "border-style:none"/> </a> </object>
Data 属性
下一个属性 data 稍微不那么明显。末尾的逗号应该放在那里。一些重要的功能是:
从技术上讲,此属性不是必需的,但 Microsoft 建议您添加它,因为某些 Web 浏览器的加载插件行为相当意外。
对象标记旨在托管嵌入内容,因此浏览器期望涉及二进制字符串、位图文件或视频或音频流等。
您通常希望在 data 属性中放置一个 URL,并且浏览器下载该数据并将其传递给插件。
data 属性采用 URI,通常它将指向某些数据,例如 JPEG 文件,但在这里,我们使用了一种稍微不寻常的 URI 方案。
<param> 标记
我们在对象内部有各种param标记,从 sourceparam开始。
<param name = "source" value = "ClientBin/DataBinding.xap"/>
它告诉插件从哪里下载 Silverlight 内容。
您应该提供一个 JavaScript 错误处理程序。如果下载过程失败,将调用此处理程序。一旦 Silverlight 代码启动并运行,如果抛出未处理的异常,也将调用此处理程序。
<param name = "onError" value = "onSilverlightError" />
所以,这不仅仅是为了加载失败的情况。您还应该指定代码所需的 Silverlight 的最低版本。
微软鼓励用户保持最新状态,因此一旦机器安装了 Silverlight 插件,新版本将通过 Windows 更新提供,但用户始终可能运行的是比您需要的版本更旧的版本。
<param name = "minRuntimeVersion" value = "5.0.61118.0" /> <param name = "autoUpgrade" value = "true" />
这个 **minRuntimeVersion** 参数允许您指定您需要的版本。如果安装的版本较旧,则会调用 onError 处理程序。
Silverlight 将数字错误代码传递给错误处理 JavaScript 函数,并且有一个不同的错误代码(碰巧是“**8001**”),用于指示插件已过期。
您可以编写 JavaScript 代码来响应此问题,或者您可以只要求插件尝试为您进行升级。
这里,**autoUpgrade** 参数设置为“**True**”,这意味着如果安装的插件已过期,Silverlight 将自动显示一条消息,告知用户需要更新的版本,并提供为其安装的选项。
备用 HTML 内容
在 param 标签之后,是如果未安装 Silverlight 则要使用的 **备用 HTML 内容**。
对于 **MIME** 类型未知的 object 标签,标准浏览器行为是将其视为 object 和 param 标签根本不存在。因此,此 a 标签及其内容将在没有 Silverlight 插件的系统中显示。
<a href = "http://go.microsoft.com/fwlink/?LinkID=149156&v=5.0.61118.0" style = "text-decoration:none"> <img src = "http://go.microsoft.com/fwlink/?LinkId=161376" alt = "Get Microsoft Silverlight" style = "border-style:none"/> </a>
请注意指向 **go.microsoft.com** 站点的两个 URL,一个超链接和一个图像。
图像链接解析为一个包含一些 Silverlight 品牌和一些提供安装 Silverlight 的文本的位图。超链接的端点相当智能。服务器检查用户代理以决定重定向的位置。
它可能会返回 Silverlight 安装可执行文件,或者如果用户在不受支持的平台上,它会将浏览器重定向到包含有关 Silverlight 信息的页面。
Silverlight.js
加载 Silverlight 内容还有另一种方法可以替代 HTML object 标签。微软提供了一个名为 **Silverlight.js** 的 JavaScript 文件,允许从浏览器脚本管理加载过程。
当您创建 Web 项目以托管新创建的 Silverlight 项目时,Visual Studio 会添加一个副本。Silverlight SDK 也包含此文件的副本。
**Silverlight.js** 的主要优点是它在未安装 Silverlight 时提供了更大的灵活性。
XAML 资源
Silverlight 还提供了一种在 XAML 中创建 **对象资源** 的机制。某些类型的对象通常通过 XAML 进行更正,您可能希望能够在应用程序中的多个位置使用它们。在多个位置使用模板非常常见。
如果您为按钮定义了自定义外观,您可能希望将其应用于多个按钮,或者甚至应用于应用程序中的所有按钮。XAML 资源系统提供了一种实现此目的的方法。您可以定义一个 **命名资源**,然后在 XAML 中的其他位置使用它。
除了模板之外,对于图形资源(如画刷和形状)也经常需要这样做。如果您的应用程序中使用了特定的配色方案,您可以将该方案的颜色和画刷定义为资源。
这是一个 **SolidColorBrush** 资源的简单应用程序。
<UserControl x:Class = "XAMLResources.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <UserControl.Resources> <SolidColorBrush x:Key = "brushResource" Color = "AliceBlue" /> </UserControl.Resources> <Grid x:Name = "LayoutRoot" Background = "White"> <StackPanel> <Rectangle Height = "50" Margin = "20" Fill = "{StaticResource brushResource}" /> <Rectangle Height = "50" Margin = "20" Fill = "{StaticResource brushResource}"/> </StackPanel> </Grid> </UserControl>
在上面的 XAML 代码中,您可以看到两个矩形都具有 **StaticResource** **brushResource** 的颜色是 **AliceBlue**。
编译并执行上述代码后,您将看到以下输出。
App.xaml
所有 Silverlight 应用程序都有一个名为 **App.xaml** 的文件。它包含应用程序范围的信息。例如,它有一个 Resources 属性,就像用户界面元素一样。
在 **App.xaml** 文件中定义的资源可在项目中的所有 XAML 文件中使用。因此,与其在 **MainPage.xaml** 中使用这些类型的资源,不如将其移至应用程序范围。
<Application xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" x:Class = "XAMLResources.App" > <Application.Resources> <SolidColorBrush x:Key = "brushResource" Color = "AliceBlue" /> </Application.Resources> </Application>
应用程序类
与大多数 XAML 文件一样,**App.xaml** 文件及其相应的 **后台代码** 文件定义了一个类。此 Application 类是 Silverlight 应用程序的入口点。**App.xaml** 通常处理应用程序范围的资源;其后台代码文件包含启动和关闭处理代码。
在创建 Application 类实例后不久,Silverlight 就会引发其 **Application.Startup** 事件。
在这里,我们创建用户界面。我们期望创建一个用户界面元素并将其分配给应用程序对象的 RootVisual 属性(在 **Startup** 事件中),这将成为 Silverlight 插件显示的用户界面。
public partial class App : Application { public App() { this.Startup += this.Application_Startup; this.Exit += this.Application_Exit; this.UnhandledException += this.Application_UnhandledException; InitializeComponent(); } private void Application_Startup(object sender, StartupEventArgs e) { this.RootVisual = new MainPage(); } private void Application_Exit(object sender, EventArgs e) {} private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) { if (!System.Diagnostics.Debugger.IsAttached) { e.Handled = true; Deployment.Current.Dispatcher.BeginInvoke(delegate { ReportErrorToDOM(e); }); } } private void ReportErrorToDOM(ApplicationUnhandledExceptionEventArgs e) { try { string errorMsg = e.ExceptionObject.Message + e.ExceptionObject.StackTrace; errorMsg = errorMsg.Replace('"', '\'').Replace("\r\n", @"\n"); System.Windows.Browser.HtmlPage.Window.Eval("throw new Error (\"Unhandled Error in Silverlight Application " + errorMsg + "\");"); } catch (Exception) {} } }
注意事项
请注意,您不能更改 **RootVisual**。您必须只设置一次。如果要在应用程序运行时更改用户界面,则必须通过更改 **MainPage** 的内容来执行此操作,而不是尝试用另一个 **MainPage** 替换它。
其他应用程序事件是 **Exit**,这是在用户界面即将消失时运行 **关闭** 代码的最后机会,以及 **UnhandledException**,如果您的代码引发未处理的异常,则会引发此事件。
如果您没有为 **UnhandledException** 事件提供处理程序,或者如果该处理程序没有将事件标记为已处理,则 **UnhandledExceptions** 将有效地关闭您的 Silverlight 应用程序。
屏幕上的插件区域将变为空白,并且会向浏览器报告脚本错误。
Silverlight - 文件访问
在本章中,我们将了解 Silverlight 应用程序如何访问最终用户计算机上的文件。在 Silverlight 中访问文件的主要方法有三种。选择将取决于您需要使用文件的原因以及您是否正在编写受信任的应用程序。
最灵活的选项是使用 **文件对话框** 类。使用 **打开** 和 **保存** 文件对话框,您可以访问最终用户选择的任何文件,只要用户具有相应的权限即可。用户同意是此方法的核心。用户必须选择要读取的文件,或者在保存时,他们选择要覆盖的文件或为您选择一个位置和文件名。
第二个选项是使用 **System.IO** 命名空间中的各种类。Silverlight 提供了诸如 **FileStream、StreamWriter、FileInfo、Directory** 和 **DirectoryInfo** 等类,所有这些类都使编写代码成为可能,该代码可以在无需用户参与的情况下打开和访问文件。这对开发人员来说可能更方便,但当然,大多数用户都不希望任何作为网页一部分下载的旧代码能够在他们的文件中搜索。
第三个选项是 **Isolated Storage**,我们将在后面讨论。
打开和保存文件对话框
SaveFileDialog
**SaveFileDialog** 类显示用于选择文件保存位置的标准操作系统提供的用户界面。
一些重要的特性是:
要使用它,我们创建 **SaveFileDialog** 类的实例。
调用 **ShowDialog** 会使其出现,返回值告诉我们用户是否选择了保存文件的位置或取消了对话框。
您可能想知道那里与 **True** 的冗余比较。如果 **ShowDialog** 返回 **True** 值,这意味着用户已选择了一个文件。因此,我们可以继续调用 **OpenFile** 方法,该方法会返回一个 **Stream**。
如果需要,我们可以发现用户选择的文件名。对话框提供了一个名为 **SafeFileName** 的属性,但它不包含路径。无论如何,写入数据的唯一方法是使用对话框返回的 **Stream**。从开发人员的角度来看,这只是一个普通的 **.NET 流**,因此我们可以将其包装在 **StreamWriter** 中,以便将文本写入其中。
OpenFileDialog
OpenFileDialog 在使用上类似于 **SaveFileDialog**。显然,您始终选择现有文件而不是新文件,但还有一个重要的区别。
它提供了一个名为 **MultiSelect** 的属性。如果将其设置为 **True**,则用户可以选择多个文件。这意味着对话框需要一个稍微复杂的 API。
**SaveFileDialog** 每次只处理一个文件,但 **OpenFileDialog** 能够处理多个文件,因此它不提供 **OpenFile** 方法。我们需要扩展代码。根据对话框是处于 **单文件** 模式还是 **MultiSelect** 模式,您可以使用其 **File** 或 **Files** 属性。
这里,在下面给出的示例中,我们处于单文件模式。因此,我们使用 **File**,并对返回的 **FileInfo** 对象调用 **OpenRead**。
在 **多选** 模式下,我们将使用 **Files**,它返回 **FileInfo** 对象的集合。
FileStream
如上所述,访问文件的第二种方法是直接使用 **FileStream** 类或 **System.IO** 命名空间中的相关类型。对此没有太多可说的,因为在大多数情况下,它类似于使用完整 **.NET Framework** 访问文件。
但是,有一些 Silverlight 特定的变化。
首先,此方法允许您在任何时候无需用户干预且没有任何明显的文件活动指示的情况下访问文件,只有受信任的应用程序才能使用此技术。请记住,您需要在浏览器外部运行才能获得提升的信任级别。
第二个问题是只有某些特定文件夹中的文件可用。您只能读取和写入位于 **用户的文档、音乐、图片或视频文件** 下面的文件。这样做的原因之一是 Silverlight 运行在多个平台上,并且例如 Apple Mac 的文件系统结构与 Windows 的文件系统结构非常不同。因此,跨平台文件访问必须根据所有 Silverlight 支持的系统上都可用的有限文件夹集来工作。
由于这些文件夹在不同的操作系统上将位于不同的位置,并且其位置通常因用户而异,因此您需要使用 **Environment.GetFolderPath** 方法在运行时发现实际位置。
您可以检查起始点下方的目录结构。**System.IO** 命名空间中的 **Directory** 和 **DirectoryInfo** 类允许您枚举文件和目录。
考虑一个简单的示例,其中文件可以通过 **OpenFileDialog** 打开并通过 **SaveFileDialog** 将一些文本保存到文件。
下面是 XAML 代码,其中创建了两个按钮和一个 **文本框**。
<UserControl x:Class = "FileDialogs.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <Grid.RowDefinitions> <RowDefinition Height = "Auto" /> <RowDefinition Height = "265*" /> </Grid.RowDefinitions> <Button x:Name = "saveFileButton" Content = "Save" Width = "75" FontSize = "20" HorizontalAlignment = "Left" VerticalAlignment = "Top" Margin = "12,12" Click = "saveFileButton_Click" /> <Button x:Name = "openFileButton" Content = "Open" Width = "75" FontSize = "20" HorizontalAlignment = "Left" VerticalAlignment = "Top" Margin = "101,12,0,0" Click = "openFileButton_Click" /> <TextBox x:Name = "contentTextBox" Grid.Row = "1" Margin = "12" FontSize = "20" /> </Grid> </UserControl>
下面是 C# 代码,用于实现单击事件,其中打开和保存文件。
using System; using System.Diagnostics; using System.IO; using System.Windows; using System.Windows.Controls; namespace FileDialogs { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void saveFileButton_Click(object sender, RoutedEventArgs e) { var save = new SaveFileDialog(); save.Filter = "Text Files (*.txt)|*.txt|All Files (*.*)|*.*"; save.DefaultExt = ".txt"; if (save.ShowDialog() == true) { Debug.WriteLine(save.SafeFileName); using (Stream saveStream = save.OpenFile()) using (var w = new StreamWriter(saveStream)) { var fs = saveStream as FileStream; if (fs != null) { w.Write(contentTextBox.Text); } } } } private void openFileButton_Click(object sender, RoutedEventArgs e) { var open = new OpenFileDialog(); if (open.ShowDialog() == true) { using (Stream openStream = open.File.OpenRead()) { using (var read = new StreamReader(openStream)) { contentTextBox.Text = read.ReadToEnd(); } } } } } }
编译并执行上述代码后,您将看到以下网页,其中包含两个按钮。
单击 **打开** 按钮,这将打开 **OpenFileDialog** 以选择文本文件。
选择一个文本文件并单击 **打开**,您将在文本框中看到文本。
要将文本保存到文件,请更新文本。
单击 **保存** 按钮将更改保存到新的文本文件或现有文件中。
要将更改保存到现有的文本文件,请在 **SaveFileDialog** 中选择文本文件,但如果要将更改保存到新文件,请写入文件名并单击 **保存** 按钮。
Silverlight - 视图模型
在本节中,我们将探讨 Silverlight 软件开发中一项重要的技术:使用**视图模型**。
**视图模型**是一个关键部分,它引入了名为分离表示的技术,通过将视图与模型分离来实现。
**视图模型**提供了一种实现分离表示的方法,我们将看到它们如何利用 Silverlight 的数据绑定来减少用户界面中所需的代码量。
UI 开发挑战
**视图模型**旨在解决在开发用户界面软件时经常出现的某些问题。也许最重要的一点是,用户界面代码通常难以进行彻底的测试,尤其是在使用自动单元测试时。还有一些代码质量问题会影响代码的持续灵活性和可维护性。
如果您遵循 Visual Studio 设计工具引导您的最简单的路径,您最终可能会在代码隐藏中放入过多的代码。
非常常见的是,大量的应用程序功能被添加到代码隐藏中。
很少有开发人员会真正计划将业务逻辑放入用户界面类中,但由于 Visual Studio 将您的事件处理程序放在那里,因此它变成了完成事情的一个过于方便的地方。
人们普遍认为,如果类具有明确定义且范围合理的职责,则软件更容易开发和维护。
代码隐藏的工作是根据需要直接与构成用户界面的对象进行交互。
一旦您开始在其中放置关于应用程序如何运行的决策代码,就会导致问题。
不仅应用程序逻辑可能会流入应该关注用户界面的代码,一些开发人员开始依赖控件和其他用户界面对象来保存重要的应用程序状态。
模型仅保存数据,视图仅保存格式化后的数据,而控制器(ViewModel)充当两者之间的联络员。控制器可能会获取来自视图的输入并将其放置在模型上,反之亦然。
分离表示
为了避免将应用程序逻辑放在代码隐藏或 XAML 中导致的问题,最好使用一种称为**分离表示**的技术。使 XAML 和代码隐藏具有与用户界面对象直接交互所需的最小功能,用户界面类还包含用于复杂交互行为、应用程序逻辑和其他所有内容的代码,如下面的左侧所示。
分离表示的重要特性 -
使用分离表示,用户界面类变得更加简单。它当然有 XAML,但代码隐藏尽可能地少。
应用程序逻辑属于一个单独的类,通常称为**模型**。
许多开发人员尝试使用数据绑定将 XAML 中的元素直接连接到模型中的属性。
问题是**模型**完全关注应用程序的功能问题,而不是用户如何与应用程序交互。
大多数用户界面都有一些不属于应用程序模型的状态。例如,如果您的用户界面使用拖放,则某些内容需要跟踪诸如当前正在拖动的项目的位置、它在移动到可能的放置目标时外观应如何更改以及这些放置目标在项目被拖动到它们上面时可能如何更改等内容。
这种状态可能会变得非常复杂,并且需要进行彻底的测试。
在实践中,您通常希望在用户界面和模型之间放置其他一些类。它有两个重要的作用。
首先,它会为特定的用户界面视图调整您的应用程序模型。
其次,它是任何非平凡交互逻辑所在的位置,我的意思是使您的用户界面按您想要的方式运行所需的代码。
模型/视图/视图模型
**视图模型**是分离表示方法的一个示例,但让我们明确说明每一层中究竟是什么样的东西。有三层 -
- 模型
- 视图
- 视图模型
模型
这是一个由普通 C# 类组成的**经典**对象模型,它与用户界面没有直接关系。
您通常会期望您的模型代码能够在不引用任何用户界面库的情况下进行编译。事实上,您可能能够获取完全相同的源代码并将其编译成 Silverlight 应用程序、普通 .NET 控制台应用程序,甚至服务器端 Web 代码。
模型中的类型应表示您的应用程序使用的概念。
视图
视图通常是 UserControl,它可能是您的 MainPage,也可能只是您页面的一部分。
在大多数 Silverlight 应用程序中,将您的用户界面拆分成小的部分,为每个部分定义一个 UserControl 或 View 是一个好主意。
Silverlight 应用程序在这方面并不独特。显然特定于 Silverlight 的是 View。您的用户界面越细粒度,事情往往就越好。您不仅不太可能遇到其他开发人员处理相同文件的麻烦,保持简洁自然会阻止导致意大利面条式代码的捷径。
例如,定义一个**视图**来表示列表中的单个项目非常常见。
视图模型
最后,对于每个**视图**,您都会编写一个**视图模型**。因此,这是**视图模型**类的一个重要特性。
它的存在是为了服务于特定的视图。**视图模型**专用于特定的呈现方式,例如列表中显示的特定数据项。
这就是为什么它被称为**视图模型**;它专门针对特定视图调整底层模型。与模型一样,**视图模型**也是一个普通的 C# 类。它不需要派生自任何特定类型。
碰巧的是,一些开发人员发现将一些通用功能放入基视图模型类中很方便,但模式并不要求这样做。特别是,您的**视图模型**不会派生自任何 Silverlight 特定类型。但是,与模型不同,它可以在其属性中使用 Silverlight 类型。
例如,您的视图模型可能会选择仅在某些条件下显示用户界面的某些部分,因此您可能会提供 System.Windows.Visibility 类型的属性,这是 Silverlight 元素用于其 Visibility 属性的类型。这使得能够将元素(例如面板)的可见性直接绑定到视图模型。
示例
让我们看一个简单的示例,我们将使用**模型-视图-视图模型 (MVVM)** 方法。
**步骤 1** - 创建一个新的 Silverlight 应用程序项目**SilverlightMVVMDemo**。
**步骤 2** - 将三个文件夹(Model、ViewModel 和 Views)添加到您的项目中,如下所示。
**步骤 3** - 在 Model 文件夹中添加一个 StudentModel 类,并将以下代码粘贴到该类中。
using System.ComponentModel; namespace SilverlightMVVMDemo.Model { public class StudentModel {} public class Student : INotifyPropertyChanged { private string firstName; private string lastName; public string FirstName { get { return firstName; } set { if (firstName != value) { firstName = value; RaisePropertyChanged("FirstName"); RaisePropertyChanged("FullName"); } } } public string LastName { get { return lastName; } set { if (lastName != value) { lastName = value; RaisePropertyChanged("LastName"); RaisePropertyChanged("FullName"); } } } public string FullName { get { return firstName + " " + lastName; } } public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string property) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(property)); } } } }
**步骤 4** - 将另一个 StudentViewModel 类添加到 ViewModel 文件夹中,并粘贴以下代码。
using SilverlightMVVMDemo.Model; using System.Collections.ObjectModel; namespace SilverlightMVVMDemo.ViewModel { public class StudentViewModel { public ObservableCollection<Student> Students { get; set; } public void LoadStudents() { ObservableCollection<Student> students = new ObservableCollection<Student>(); students.Add(new Student { FirstName = "Mark", LastName = "Allain" }); students.Add(new Student { FirstName = "Allen", LastName = "Brown" }); students.Add(new Student { FirstName = "Linda", LastName = "Hamerski" }); Students = students; } } }
**步骤 5** - 通过右键单击**Views**文件夹并选择**添加新项…**来添加**Silverlight 用户控件**。
**步骤 6** - 点击添加。现在您将看到 XAML 文件。将以下代码添加到**StudentView.xaml**文件中,其中包含不同的 UI 元素。
<UserControl x:Class = "SilverlightMVVMDemo.Views.StudentView" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <StackPanel HorizontalAlignment = "Left"> <ItemsControl ItemsSource = "{Binding Path=Students}"> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel Orientation = "Horizontal"> <TextBox Text = "{Binding Path = FirstName, Mode = TwoWay}" Width = "100" Margin = "3 5 3 5"/> <TextBox Text = "{Binding Path = LastName, Mode = TwoWay}" Width = "100" Margin = "0 5 3 5"/> <TextBlock Text = "{Binding Path = FullName, Mode=OneWay}" Margin = "0 5 3 5"/> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </StackPanel> </Grid> </UserControl>
**步骤 7** - 现在将**StudentView**添加到您的**MainPage.xaml**文件中,如下所示。
<UserControl x:Class = "SilverlightMVVMDemo.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:views = "clr-namespace:SilverlightMVVMDemo.Views" mc:Ignorable = "d" d:DesignHeight = "576.316" d:DesignWidth = "863.158"> <Grid x:Name = "LayoutRoot" Background = "White"> <views:StudentView x:Name = "StudentViewControl" Loaded = "StudentViewControl_Loaded"/> </Grid> </UserControl>
**步骤 8** - 这是**MainPage.xaml.cs**文件中**Loaded**事件的实现,它将从**ViewModel**更新**View**。
using System.Windows; using System.Windows.Controls; namespace SilverlightMVVMDemo { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } } private void StudentViewControl_Loaded(object sender, RoutedEventArgs e) { SilverlightMVVMDemo.ViewModel.StudentViewModel studentViewModelObject = new SilverlightMVVMDemo.ViewModel. StudentViewModel(); studentViewModelObject.LoadStudents(); StudentViewControl.DataContext = studentViewModelObject; } }
**步骤 9** - 当以上代码编译并执行时,您将在网页上看到以下输出。
UI 与视图模型
MVVM 方法中最难的部分之一是确定分界线应该在哪里。哪些东西属于哪里并不总是显而易见的。
特别是,一些用户界面元素提供了功能,根据严格的视图,这些功能可以说应该属于视图模型。
一般来说,并非在**视图**中实现的所有行为都那么**视图模型**友好。
部分原因是,没有标准的方式来打包视图模型行为以供重用,尤其是在您想要使用设计环境(如 Visual Studio 或 Blend)时。
MVVM 的优点
MVVM 提供以下优点 -
分离表示关注点(视图、视图模型、模型)
干净的可测试和可管理的代码。可以在单元测试中包含表示层逻辑。
没有代码隐藏代码,因此表示层和逻辑是松耦合的。
更好的数据绑定方式。
MVVM 的缺点
对于简单的 UI,MVVM 可能有点过头了。当我们有复杂的数据绑定时,调试会有点困难。
Silverlight - 输入处理
在本节中,我们将学习如何在 Silverlight 应用程序中处理用户输入。Silverlight 提供了一个强大的 API,应用程序可以通过该 API 获取来自各种设备(如鼠标、键盘和触摸等)的输入。
输入类型
用户可以通过多种不同的方式与您的应用程序交互。最明显的方式是使用鼠标。Silverlight 提供了用于跟踪以下内容的事件 -
- 鼠标移动
- 按钮点击,以及
- 滚轮活动
当然还有键盘,Silverlight 还支持触摸屏输入。如果您熟悉 Windows 中的触摸支持,您就会知道触摸输入可以表示为提供详细信息的低级事件,也可以将其总结为称为手势的高级事件。
鼠标事件
让我们从查看 Silverlight 提供的鼠标输入事件开始。一些事件与鼠标指针的移动有关。
只要指针在您已附加处理程序的元素上移动,就会引发MouseMove 事件。
您还可以获得MouseEnter 和MouseLeave 事件,以通知您鼠标何时移入和移出元素。
以下是添加椭圆和文本块的 XAML 代码。
<UserControl x:Class="MouseInput.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <TextBlock x:Name = "mouseText" FontSize = "40" VerticalAlignment = "Top" Height = "76" Margin = "0,10,0,0" /> <Ellipse Name = "myEllipse" Width = "320" Height = "150" HorizontalAlignment = "Left" VerticalAlignment = "Top" Margin = "27,103,0,0" Stroke = "Black" StrokeThickness = "10" Fill = "#00FF0000" MouseEnter = "myEllipse_MouseEnter" MouseLeave = "myEllipse_MouseLeave" MouseMove = "myEllipse_MouseMove" /> </Grid> </UserControl>
以下是不同鼠标输入事件的实现。
using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace MouseInput { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void myEllipse_MouseEnter(object sender, MouseEventArgs e) { mouseText.Text = "Mouse Enter"; myEllipse.Stroke = new SolidColorBrush(Colors.Blue); } private void myEllipse_MouseLeave(object sender, MouseEventArgs e) { mouseText.Text = "Mouse Leave"; myEllipse.Stroke = new SolidColorBrush(Colors.Black); } private void myEllipse_MouseMove(object sender, MouseEventArgs e) { mouseText.Text = "Mouse Move: " + e.GetPosition(myEllipse); } } }
编译并执行上述代码后,您将看到以下输出。
当鼠标进入椭圆时,您将看到颜色和坐标的变化。
当鼠标离开椭圆时,它将显示消息“mouse leave”,并更改为默认颜色。
键盘
用户向您的应用程序输入文本数据的最简单方法是通过键盘(如果可用)。请记住,并非所有移动设备都配备键盘,除了笔记本电脑和台式机。
Silverlight 提供了两个用于键盘输入的简单事件,KeyUp 和KeyDown。
这两个事件都将KeyEventArgs 传递给处理程序,而 Key 属性指示按下的是哪个键。
在下面的示例中,处理了一些键盘输入。
以下示例定义了 Click 事件的处理程序和KeyDown 事件的处理程序。
以下是添加不同 UI 元素的 XAML 代码。
<UserControl x:Class = "KeyboardInput.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <StackPanel Orientation = "Horizontal" KeyDown = "OnTextInputKeyDown"> <TextBox Width = "400" Height = "30" Margin = "10"/> <Button Click = "OnTextInputButtonClick" Content = "Open" Margin = "10" Width = "50" Height = "30"/> </StackPanel> </Grid> </UserControl>
以下是处理不同键盘和单击事件的 C# 代码。
using System.Windows; using System.Windows.Controls; using System.Windows.Input; namespace KeyboardInput { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void OnTextInputKeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.O) { handle(); e.Handled = true; } } private void OnTextInputButtonClick(object sender, RoutedEventArgs e) { handle(); //e.Handled = true; } public void handle() { MessageBox.Show("Do you want to open a file?"); } } }
编译并执行上述代码后,您将看到以下内容:
如果单击打开按钮或在文本框中单击并单击确定,则它将显示相同的消息。
我们建议您执行以上示例以更好地理解。
Silverlight - 隔离存储
第三种文件访问机制是Isolated Storage 机制,它提供与登录用户关联的存储。API 通过来自.NET System.IO 命名空间的Stream 类呈现数据。因此,与我们迄今为止查看的其他机制一样,您可以使用System.IO 中的其他类型来处理流,从而使您能够存储文本或二进制数据。
一些重要的特性是:
这种存储机制称为Isolated Storage,因为存储是分区的,Silverlight 应用程序只能访问某些部分。
您无法访问任何旧的存储数据。首先,存储按用户分区。Silverlight 应用程序无法访问与登录和运行应用程序的用户不同的用户的存储。
这与您的 Web 应用程序可能使用的任何身份验证机制无关。这一点很重要,因为一些共享计算机的人不使用单独的 Windows 帐户,并且习惯于仅登录和注销他们使用的网站。
使用 Isolated Storage
Isolated Storage 并非 Silverlight 独有。该 API 最初是为了Windows 窗体而引入的,以便从 Web 启动的应用程序能够在部分信任场景中本地存储数据。实现方式不同,无法从 Silverlight 访问完整的.NET Framework 的 Isolated Storage,反之亦然。
但是,如果您使用过它,这里的步骤看起来会非常熟悉。
您首先请求用户特定的存储。在这种情况下,我们请求应用程序的存储。如果我们想要由站点上的所有 XAP 共享的每个站点的存储,我们将调用GetUserStoreForSite 而不是此方法。
这两种方法都会返回一个IsolatedStorageFile 对象,这是一个非常无用的名称,因为它表示一个目录,而不是一个文件。
要访问文件,您需要向IsolatedStorageFile 请求一个Stream。
我们使用IsolatedStorageFileStream 类,其构造函数要求您将IsolatedStorageFile 对象作为参数传递。
因此,我们正在存储中创建新文件。文件在磁盘上的确切位置未知。
包含目录包含随机元素,以使其无法猜测文件名称。
如果没有此功能,恶意网站可能会将文件放置在用户的计算机上,然后构建文件 URL 以打开它,希望诱骗用户单击本地执行程序的链接。
Windows 中内置了各种其他安全措施来防止这种情况发生,但这是另一层防御措施,以防其他措施被禁用或绕过。
该文件将存储在用户配置文件的某个位置,但您只能知道这一点。您的IsolatedStorageFileStream 不会报告其真实位置。
让我们来看一个简单的示例,该示例跟踪应用程序运行的次数。以下是 XAML 代码。
<UserControl x:Class = "StoreRunCount.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <TextBlock x:Name = "runCountText" FontSize = "20" /> </Grid> </UserControl>
以下是使用Isolated storage 的 C# 代码。
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.IO.IsolatedStorage; using System.IO; namespace StoreRunCount { public partial class MainPage : UserControl { const string RunCountFileName = "RunCount.bin"; public MainPage() { InitializeComponent(); int runCount = 0; using (var store = IsolatedStorageFile.GetUserStoreForApplication()) { if (store.FileExists(RunCountFileName)) { using (var stm = store.OpenFile(RunCountFileName, FileMode.Open, FileAccess.Read)) using (var r = new BinaryReader(stm)) { runCount = r.ReadInt32(); } } runCount += 1; using (var stm = store.OpenFile(RunCountFileName, FileMode.Create, FileAccess.Write)) using (var w = new BinaryWriter(stm)) { w.Write(runCount); } } runCountText.Text = "You have run this application " + runCount.ToString() + " time(s)"; } } }
编译并执行上述代码后,您将看到以下网页,它将向您显示运行此应用程序的次数。
增加配额
如果初始空间不足,应用程序可能会请求更多空间。无法保证请求一定会成功。Silverlight 将询问用户是否同意为应用程序提供更多空间。
顺便说一句,您只能响应用户输入(例如单击)时才能请求更多存储空间。如果您尝试在其他时间(例如插件加载时或在计时器处理程序中)请求它,Silverlight 将自动失败该请求,甚至不会提示用户。额外的配额仅适用于用户正在与之交互的应用程序。
IsolatedStorageFile 对象提供三个用于管理配额的成员:
- AvailableFreeSpace
- IncreaseQuotaTo
- Quota
AvailableFreeSpace
AvailableFreeSpace 属性告诉您剩余多少配额。
请注意,即使是空子目录也会占用一些配额,因为操作系统需要在磁盘上分配空间来表示该目录。因此,可用空间可能小于总配额减去所有文件的大小总和。
IncreaseQuotaTo
如果您没有足够的空间继续,则可以通过调用IncreaseQuotaTo 方法来请求更多空间。
Quota
这里我们使用第三个属性Quota 来发现当前配额大小,然后添加我们需要获得新请求配额的额外数量。
该方法返回True 或False 以指示我们是否分配了我们请求的内容。请注意,Silverlight 可能会决定分配比您请求的更多空间。
以下是一个简单的示例,用于在单击按钮时增加配额。以下是 XAML 代码。
<UserControl x:Class = "ChangeQuota.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <TextBlock x:Name = "infoText" FontSize = "20" TextWrapping = "Wrap" /> <Button x:Name = "increaseQuota" Content = "Increase" HorizontalAlignment = "Center" FontSize = "20" VerticalAlignment = "Center" Click = "increaseQuota_Click" /> </Grid> </UserControl>
以下是增加配额的click 事件的实现。
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.IO.IsolatedStorage; namespace ChangeQuota { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void increaseQuota_Click(object sender, RoutedEventArgs e) { using (IsolatedStorageFile isoStore = IsolatedStorageFile.GetUserStoreForApplication()) { long newQuota = isoStore.Quota + 10240; if (isoStore.IncreaseQuotaTo(newQuota)) { infoText.Text = "Quota is " + isoStore.Quota + ", free space: " + isoStore.AvailableFreeSpace; } else { infoText.Text = "Meanie!"; } } } } }
编译并执行上述代码后,您将看到以下输出。
单击增加时,将显示提示。它要求将配额增加到比其当前值大 10KB。
单击是后,它将打印出可用的配额数量。
我们建议您执行以上示例以更好地理解。
Silverlight - 文本
在本章中,我们将了解 Silverlight 提供了哪些功能来显示文本。文本块用于所有文本呈现和 Silverlight。其他重要功能包括:
- 它可以用于简单的纯文本,也可以应用各种格式样式的混合。
- Silverlight 支持一组标准的内置字体。
- 当您的应用程序视觉样式需要一些不寻常的东西时,您还可以下载自定义字体。
TextBlock
要显示文本,我们使用 Silverlight 文本框元素,它是一个轻量级控件,用于显示少量只读文本。事实上,我们已经多次看到它,因为它的基本用法实际上不需要太多解释。您只需设置 text 属性,它就会为您显示该文本。
<TextBlock Text = "Print Testing" HorizontalAlignment Center" FontFamily = "Georgia"/>
TextBlock 类的层次继承如下:
以下是TextBlock 类常用的属性。
序号 | 属性和描述 |
---|---|
1 | ContentEnd 获取 TextBlock 中文本内容末尾的 TextPointer 对象。 |
2 | ContentStart 获取 TextBlock 中文本内容开头的 TextPointer 对象。 |
3 | IsTextSelectionEnabled 获取或设置一个值,该值指示是否在 TextBlock 中启用了文本选择,无论是通过用户操作还是调用与选择相关的 API。 |
4 | IsTextSelectionEnabledProperty 标识 IsTextSelectionEnabled 依赖项属性。 |
5 | LineHeight 获取或设置内容每一行的高度。 |
6 | MaxLines 获取或设置 TextBlock 中显示的最大文本行数。 |
7 | SelectedText 获取所选文本的文本范围。 |
8 | SelectionEnd 获取 TextBlock 中所选文本的结束位置。 |
9 | SelectionHighlightColor 获取或设置用于突出显示所选文本的画刷。 |
10 | SelectionStart 获取 TextBlock 中所选文本的起始位置。 |
11 | Text 获取或设置 TextBlock 的文本内容。 |
12 | TextAlignment 获取或设置一个值,该值指示文本内容的水平对齐方式。 |
13 | TextTrimming 获取或设置当内容超出内容区域时要采用的文本修剪行为。 |
14 | TextWrapping 获取或设置 TextBlock 如何换行文本。 |
以下是TextBlock 类常用的事件。
序号 | 事件及说明 |
---|---|
1 | ContextMenuOpening 当系统处理显示上下文菜单的交互时发生。 |
2 | SelectionChanged 文本选择发生更改时发生。 |
以下是TextBlock 类常用的方法。
序号 | 方法及描述 |
---|---|
1 | Focus 将焦点设置到 TextBlock 上,就像它是常规的可聚焦控件一样。 |
2 | Select 选择 TextBlock 中的一段文本。 |
3 | SelectAll 选择 TextBlock 中的全部内容。 |
Run
有时您希望对格式进行细粒度控制,并为整个文本块设置一种样式。有时对单个单词甚至字母进行格式化很有用,如果您想要这样做,那么不要使用Text 属性,而是将文本作为内容放在TextBlock 中。如果您使用代码,则对应于向TextBlock 内联属性添加项。
使用这种方法,您可以添加一系列 run 元素。每个 Run 都支持相同的字体系列、字体粗细、前景色等属性来控制文本样式。尽管 Run 是一个单独的元素,但这不会中断流程。
让我们来看一个简单的示例,它包含TextBlock 内部的多个Run 元素。以下是 XAML 代码。
<UserControl x:Class = "SilverlightRunDemo.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <TextBlock Width = "192" TextWrapping = "Wrap" FontFamily = "Verdana"> <Run Text = "Hello, " /> <Run FontWeight = "Bold" Text = "world!" /> <Run Text = "You" /> <Run FontStyle = "Italic" Text = " are " /> <Run Text = "learning" FontSize = "40" FontFamily = "01d English Text MT" /> <Run Text = " the " /> <Run Text = "basics of " Foreground = "Blue" /> <Run Text = " Silverlight." FontSize = "30" /> </TextBlock> </Grid> </UserControl>
编译并执行上述代码后,您将看到以下输出。
如您所见,此文本块通过使用Run 元素以不同的格式样式进行排列。
顺便说一句,您不需要将每一小段文本都包装在 run 中。您可以将文本块的大部分内容保留为纯文本,只需对需要不同格式的部分应用run,如下所示。
<TextBlock> Hello, <Run FontWeight = "Bold" Text =" world!"/> </TextBlock>
LineBreak
Silverlight 通常会忽略 XAML 中的换行符。它假设大多数空格是为了使它们更易于阅读,因为您实际上希望该空格出现。
让我们来看一下这段 XAML 代码,它包含三行单独的文本。
<TextBlock> This is not the end. It is not even the beginning of the end. But it is, perhaps, the end of the beginning </TextBlock>
编译并执行上述代码后,您将看到以下输出。
如您所见,它忽略了换行符,并将所有文本一起执行。
如果启用文本换行,它将在需要换行以使文本适合的地方插入换行符,但它会忽略示例中的换行符。
如果您只想添加显式换行符,则需要在文本块内添加换行符标记。其后的文本将从新行开始。
让我们再次查看相同的示例,方法是添加LineBreak 标记。
<TextBlock FontSize = "16"> This is not the end. <LineBreak/> It is not even the beginning of the end. <LineBreak/> But it is, perhaps, the end of the beginning </TextBlock>
执行上述代码后,您将看到它现在看起来与 XAML 中指定的相同。
内置字体
Silverlight 有一组固定的内置字体系列。由于历史原因,这些字体的字体系列名称实际上有所不同。默认字体系列在 Mac OS 和 Windows 上在技术上是不同的,例如在 Mac OS 上它是 Lucida Grande,而在 Windows 上它是几乎相同但命名为 Lucida Sans Unicode 的字体。
下面给出了一些最常用的字体。
字体 |
---|
Arial |
Arial Black |
Comic Sans MS |
Courier New |
Georgia |
Lucida Grande (Mac) 或 Lucida Sans Unicode (Windows) |
Times New Roman |
Trebuchet MS |
Verdana |
Silverlight - 动画
动画允许您创建真正动态的用户界面。它通常用于应用效果,例如,您移动鼠标时增大的图标、旋转的徽标、滚动到视图中的文本等等。
有时,这些效果看起来像是过度的炫耀。如果使用得当,动画可以多种方式增强应用程序。它们可以让应用程序看起来更具响应性、更自然和更直观。
例如,当您单击时滑入的按钮感觉像一个真实的物理按钮,而不仅仅是另一个灰色的矩形。动画还可以吸引用户注意重要元素,并指导用户过渡到新内容。
Silverlight 的动画方法是声明式的,而不是专注于帧动画的序列。
定义动画
动画通常在资源部分定义。实际上,它们通常包装在一个故事板元素中,我们很快就会详细了解。
它提供了一个 Begin() 方法,因此可以从代码中调用动画。
动画也可以放在控件模板中的视觉状态元素内部。
声明式动画
Silverlight 中的动画是声明式的。它们描述了您希望发生的事情。让 Silverlight 自己解决如何实现它。因此,动画通常遵循以下模式:我们告诉 Silverlight 我们希望更改什么。
这始终是某些命名元素上的一些属性,即 **TargetName** 和 **TargetProperty**。
<DoubleAnimation Storyboard.TargetName = "myRectangle" Storyboard.TargetProperty = "Opacity" From = "0" To = "1" Duration = "0:0:5" />
我们说明我们希望该属性如何更改,在这种情况下,我们将不透明度从值 0 更改为值 1。换句话说,我们希望目标元素从不透明淡化为透明。
最后,我们说明我们希望这需要多长时间,在这种情况下,将需要 5 秒。
此双动画中的双精度数的意义在于它针对一个类型为双精度数的属性,即浮点值。
如果您想动画化表示颜色的属性,则可以使用颜色动画。
让我们来看一个双动画的简单示例。下面是 XAML 代码,其中添加了两个按钮、一个矩形和两个故事板。
<UserControl x:Class = "DoubleAnimationExample.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignWidth = "640" d:DesignHeight = "480"> <UserControl.Resources> <Storyboard x:Name = "fadeDown"> <DoubleAnimation Storyboard.TargetName = "myRectangle" Storyboard.TargetProperty = "Opacity" From = "1" To = "0" Duration = "0:0:5" /> </Storyboard> <Storyboard x:Name = "fadeUp"> <DoubleAnimation Storyboard.TargetName = "myRectangle" Storyboard.TargetProperty = "Opacity" From = "0" To = "1" Duration = "0:0:5" /> </Storyboard> </UserControl.Resources> <Grid x:Name = "LayoutRoot"> <Rectangle x:Name = "myRectangle" Fill = "Blue" Width = "300" Height = "100" HorizontalAlignment = "Center" VerticalAlignment = "Top" Margin = "0,30" /> <Button x:Name = "fadeUpButton" Content = "Up" Width = "80" Height = "30" HorizontalAlignment = "Left" VerticalAlignment = "Top" Margin = "50,140,0,0" Click = "fadeUpButton_Click" /> <Button x:Name = "fadeDownButton" Content = "Down" Width = "80" Height = "30" HorizontalAlignment = "Left" VerticalAlignment = "Top" Margin = "50,180,0,0" Click = "fadeDownButton_Click" /> </Grid> </UserControl>
以下是 C# 中不同事件的实现。
using System.Windows; using System.Windows.Controls; namespace DoubleAnimationExample { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void fadeUpButton_Click(object sender, RoutedEventArgs e) { fadeUp.Begin(); } private void fadeDownButton_Click(object sender, RoutedEventArgs e) { fadeDown.Begin(); } } }
编译并执行上述代码后,您将看到以下输出。
重复和反转
动画提供了一些属性来自动重复和全部反转动画。
如果将 RepeatBehavior 属性设置为时间跨度,则动画将循环重复,直到指定的持续时间过去,或者您也可以只告诉它希望它重复多少次。
这支持小数点,因此您可以重复 4.5 次。
您可以永远重复,也可以告诉动画,一旦它到达结尾,它应该反向运行回到开始。
关键帧动画
通常,从 A 到 B 的简单动画过于简单。例如,您想动画化一个球弹离地面。这不是简单的点到点运动。球体下降,速度逐渐加快,然后在触底时反转方向。在回到其行程的顶部时再次减速。
让我们来看一个 **关键帧动画** 的简单示例。
下面是 XAML 代码,其中包含一个椭圆和带有关键帧的双动画。
<UserControl x:Class = "LinearKeyFrames.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" Width = "400" Height = "300"> <UserControl.Resources> <Storyboard x:Name = "ballAnim" SpeedRatio = "0.2"> <DoubleAnimation From = "0" Duration = "00:00:03" To = "96" Storyboard.TargetName = "ellipse" Storyboard.TargetProperty = "(Canvas.Left)" /> <DoubleAnimationUsingKeyFrames Storyboard.TargetName = "ellipse" Storyboard.TargetProperty = "(Canvas.Top)"> <LinearDoubleKeyFrame KeyTime = "00:00:00" Value = "0"/> <LinearDoubleKeyFrame KeyTime = "00:00:00.5" Value = "16" /> <LinearDoubleKeyFrame KeyTime = "00:00:01" Value = "48"/> <LinearDoubleKeyFrame KeyTime = "00:00:01.5" Value = "112"/> <LinearDoubleKeyFrame KeyTime = "00:00:02" Value = "48"/> <LinearDoubleKeyFrame KeyTime = "00:00:02.5" Value = "16"/> <LinearDoubleKeyFrame KeyTime = "00:00:03" Value = "0"/> </DoubleAnimationUsingKeyFrames> </Storyboard> </UserControl.Resources> <Grid x:Name = "LayoutRoot" Background = "White"> <Canvas> <Ellipse x:Name = "ellipse" Fill = "Aqua" Width = "50" Height = "50" /> </Canvas> </Grid> </UserControl>
以下是 **鼠标左键** 按下事件的实现,当用户在网页上按下鼠标左键时,它将开始动画。
using System.Windows.Controls; using System.Windows.Input; namespace LinearKeyFrames { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); this.MouseLeftButtonDown += new MouseButtonEventHandler(Page_MouseLeftButtonDown); } void Page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { ballAnim.Begin(); } } }
编译并执行上述代码后,您将看到以下输出。
当您单击网页时,您将看到球开始移动。
Silverlight - 视频和音频
在本章中,我们将了解 Silverlight 功能如何播放视频和音频。**MediaElement** 是 Silverlight 中所有视频和音频的核心。这允许您在应用程序中集成音频和视频。**MediaElement** 类的工作方式类似于 **Image** 类。您只需将其指向媒体,它就会呈现音频和视频。
主要区别在于它将是移动图像,但如果您将其指向仅包含音频而不包含视频的文件(例如 MP3),它将在不显示任何屏幕内容的情况下播放该音频。
MediaElement 作为 UI 元素
**MediaElement** 派生自框架元素,它是所有 Silverlight 用户界面元素的基类。这意味着它提供了所有标准属性,因此您可以修改其不透明度,可以设置剪辑或对其进行转换等等。
让我们来看一个 **MediaElement** 的简单示例。
打开 Microsoft Blend for Visual Studio 并创建一个新的 Silverlight 应用程序项目。
现在将视频或音频文件拖放到 Blend 设计图面。
它将向图面添加一个 MediaElement,并在您的项目中添加视频文件的副本。您可以在解决方案资源管理器中看到它。
您可以将其移动到周围,更改其大小,您可以执行诸如应用旋转等操作。
现在,它将在 **MainPage.xaml** 文件中为您生成相关的 XAML,如下所示。
<UserControl x:Class = "MediaElementDemo.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <MediaElement x:Name = "Microsoft_Silverlight_DEMO_mp4" Margin = "51,49,53,53" Source = "/Microsoft Silverlight DEMO.mp4" Stretch = "Fill" RenderTransformOrigin = "0.5,0.5"> <MediaElement.RenderTransform> <CompositeTransform Rotation = "-18.384"/> </MediaElement.RenderTransform> </MediaElement> </Grid> </UserControl>
编译并执行上述应用程序后,您将看到视频正在您的网页上播放。
控制
**MediaElement** 仅呈现媒体。它不提供任何标准播放器控件。它自动开始播放并在到达结尾时停止,用户无法执行暂停或其他控制操作。因此,在实践中,大多数应用程序都希望为用户提供更多控制权。
您可以通过将 **AutoPlay** 设置为 **False** 来禁用自动播放。这意味着媒体播放器在您要求之前不会播放任何内容。
<MediaElement x:Name = "Microsoft_Silverlight_DEMO_mp4" AutoPlay = "False" Margin = "51,49,53,53" Source = "/Microsoft Silverlight DEMO.mp4" Stretch = "Fill" RenderTransformOrigin = "0.5,0.5">
因此,当您想播放视频时,您可以直接调用 **MediaElement Play() 方法**。它还提供停止和暂停方法。
让我们再次查看相同的示例,并对其进行一些修改以允许一些控制。在 **MediaElement** 中附加 **MouseLeftButtonDown** 处理程序,如以下 XAML 代码所示。
<UserControl x:Class = "MediaElementDemo.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <MediaElement x:Name = "Microsoft_Silverlight_DEMO_mp4" AutoPlay = "False" MouseLeftButtonDown = "Microsoft_Silverlight_DEMO_mp4_MouseLeftButtonDown" Margin = "51,49,53,53" Source = "/Microsoft Silverlight DEMO.mp4" Stretch = "Fill" RenderTransformOrigin = "0.5,0.5"> </MediaElement> </Grid> </UserControl>
以下是 **MouseLeftButtonDown** 事件处理程序的实现,它将检查媒体元素的当前状态是否正在播放,如果是则暂停视频,否则开始播放视频。
using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media; namespace MediaElementDemo { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void Microsoft_Silverlight_DEMO_mp4_MouseLeftButtonDown (object sender, MouseButtonEventArgs e) { if (Microsoft_Silverlight_DEMO_mp4.CurrentState == MediaElementState.Playing) { Microsoft_Silverlight_DEMO_mp4.Pause(); } else { Microsoft_Silverlight_DEMO_mp4.Play(); } } } }
编译并执行上述代码后,您将看到空白的网页,因为我们已将 **AutoPlay** 属性设置为 **False**。当您单击网页时,它将开始播放视频。
当您再次单击网页时,它将暂停视频。
Silverlight - 打印
打印对于某些类型的应用程序而言是一项重要的功能。在本章中,我们将了解 Silverlight 中的相关功能。
打印 API,以及所有 Silverlight 应用程序如果要打印必须执行的基本步骤。选择水印的各种选项。
最简单的方法是打印屏幕上已有的用户界面元素的副本。
大多数应用程序都希望比这更高级,并生成专门用于打印的内容,在某些情况下,需要将内容拆分为多个页面。
打印步骤
无论您是打印屏幕截图还是屏幕上已有的内容,还是进行完全自定义的多页打印输出,都需要执行相同的基本步骤。
打印 API 的核心是 PrintDocument 类。
您首先构造其中一个,当您调用其 Print 方法时,它将显示启动打印作业的标准用户界面。
用户可以像往常一样选择打印机并配置设置。如果用户随后通过单击 **打印** 决定继续,则 **PrintDocument** 将立即引发其 **PrintPage** 事件,并且您对该事件的处理程序将提供要打印的内容。
事件参数为此目的提供了一个 **PageVisual** 属性。
您可以将其设置为任何 Silverlight 用户界面元素,无论是屏幕上已可见的元素,还是专门为打印创建的新元素。
打印现有元素
元素最简单的选项是打印 Silverlight 应用程序中屏幕上已有的内容。由于 **PrintPage** 事件参数 **PageVisual** 接受任何用户界面元素,因此您可以选择用户界面中的任何内容并进行打印。
这与使用 PrintScreen 键截取屏幕截图仅有一小步之遥。它比这稍微好一点,因为用户不必手动将屏幕截图粘贴到其他程序中进行裁剪和打印。它仍然只是一次轻微的改进。
打印屏幕上已有的内容存在问题。
首先,无法保证在屏幕上有效的布局在纸张上也能很好地工作。
让我们来看一个简单的示例,其中 **ScrollViewer** 包含一些 UI 元素,其布局适合屏幕。它根据浏览器窗口大小调整大小,并提供滚动条以确保即使不适合也能访问所有内容。
下面是 XAML 代码。
<UserControl xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:sdk = "http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class = "SilverlightPrinting.MainPage" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "500"> <Grid x:Name = "LayoutRoot" Background = "White"> <Button x:Name = "print" Content = "Print" Click = "print_Click" Width = "60" Height = "20" Margin = "10,10,430,270"/> <ScrollViewer x:Name = "myScrollViewer" HorizontalScrollBarVisibility = "Auto" VerticalScrollBarVisibility = "Auto" Width = "400" Margin = "90,0,10,0"> <StackPanel> <Rectangle Fill = "Gray" Width = "100" Height = "100" /> <Button x:Name = "button" Content = "Button" Width = "75"/> <sdk:Calendar Height = "169" Width = "230"/> <Rectangle Fill = "AliceBlue" Width = "475" Height = "100" /> </StackPanel> </ScrollViewer> </Grid> </UserControl>
以下是 **打印** 按钮的单击事件实现,它将打印 **ScrollViewer** 及其可见数据。
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Printing; namespace SilverlightPrinting { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void print_Click(object sender, RoutedEventArgs e) { PrintDocument pd = new PrintDocument(); pd.PrintPage += new System.EventHandler<PrintPageEventArgs>(pd_PrintPage); pd.Print("Print Screen Content"); } private void pd_PrintPage(object sender, PrintPageEventArgs e) { e.PageVisual = myScrollViewer; } } }
如您所见,在 **打印按钮单击事件** 中创建了 **PrintDocument** 对象,我们将一个处理程序附加到其 PrintPage 事件。
您可以将 **PageVisual** 属性设置为引用 **ScrollViewer**。
然后调用 **Print 方法**。这将采用一个字符串,该字符串将在打印队列中显示为作业名称。
编译并执行上述代码后,您将看到以下输出。
当您单击 **打印** 按钮时,您将看到标准的打印对话框。
现在,选择默认打印机。为了演示目的,让我们选择 **OneNote** 并单击 **打印** 按钮。您将看到 **ScrollViewer** 已打印。
请注意,滚动条仍显示在 **ScrollViewer** 上。
自定义 UI 树
与其打印屏幕上已有的内容,通常更有意义的是专门为打印构建一个用户界面元素树。这样,您可以确保在纸上只使用非交互式元素,并且可以创建更适合纸张形状和尺寸的专用布局。您可以创建一个专门用于打印的 UserControl。
让我们来看一个简单的例子,创建一个 Silverlight 项目并添加一个名为PrintLayout的UserControl。
将设计时宽度和高度设置为大约纸张的形状。以下是PrintLayout.xaml文件的 XAML 代码。
<UserControl x:Class = "PrintCustomUI.PrintLayout" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "768" d:DesignWidth = "960"> <Grid x:Name = "LayoutRoot" Background = "White"> <Grid.RowDefinitions> <RowDefinition Height = "Auto" /> <RowDefinition /> <RowDefinition Height = "Auto" /> </Grid.RowDefinitions> <TextBlock Text = "Silverlight" HorizontalAlignment = "Center" FontSize = "60" FontWeight = "Bold" FontFamily = "Georgia" /> <TextBlock Grid.Row = "2" Text = "Print Testing" HorizontalAlignment = "Center" FontFamily = "Georgia" FontSize = "24" Margin = "0,10"/> <Rectangle Grid.Row = "2" Height = "1" Fill = "Black" VerticalAlignment = "Top"/> <Ellipse Grid.Row = "1" Stroke = "Black" StrokeThickness = "10" Margin = "10"> <Ellipse.Fill> <RadialGradientBrush GradientOrigin = "0.2,0.2" Center = "0.4,0.4"> <GradientStop Color = "Aqua" Offset = "0.006" /> <GradientStop Color = "AntiqueWhite" Offset = "1" /> </RadialGradientBrush> </Ellipse.Fill> </Ellipse> </Grid> </UserControl>
以下是MainPage.xaml文件中的代码,其中仅包含一个Print按钮。
<UserControl x:Class = "PrintCustomUI.MainPage" xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d = "http://schemas.microsoft.com/expression/blend/2008" xmlns:mc = "http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable = "d" d:DesignHeight = "300" d:DesignWidth = "400"> <Grid x:Name = "LayoutRoot" Background = "White"> <Button Content = "Print..." Height = "23" HorizontalAlignment = "Left" Margin = "12,28,0,0" Name = "printButton" VerticalAlignment = "Top" Width = "75" Click = "printButton_Click" /> </Grid> </UserControl>
以下是打印按钮的Click 事件实现。
using System; using System.Collections.Generic; using System; using System.Windows; using System.Windows.Controls; using System.Windows.Printing; namespace PrintCustomUI { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void printButton_Click(object sender, RoutedEventArgs e) { PrintDocument pd = new PrintDocument(); pd.PrintPage += new EventHandler<PrintPageEventArgs>(pd_PrintPage); pd.Print("Custom"); } void pd_PrintPage(object sender, PrintPageEventArgs e) { var pl = new PrintLayout(); pl.Width = e.PrintableArea.Width; pl.Height = e.PrintableArea.Height; e.PageVisual = pl; } } }
编译并执行上述代码后,您将在网页上看到以下输出。
点击Print并选择OneNote打印布局。您将看到布局已打印。
您可以看到它已经填充了可用空间。我们建议您执行以上示例以更好地理解。