SilverLight 的 FAQ - 第 3 部分






4.76/5 (12投票s)
关于绑定、布局、使用 WCF 服务以及如何通过 Silverlight 连接数据库的常见问题解答
更新:其他文章的链接已移至本文底部。
目录
- 引言
- 您能解释一下单向绑定和双向绑定吗?
- 您能解释一下一次性绑定吗?
- 您能演示一个单向和双向绑定的简单示例吗?
- SilverLight 中提供了哪些不同的布局方式?
- 您能解释一下 Canvas 布局是如何工作的吗?
- 如何实现 Grid 布局?
- 如何实现 Stack 布局?
- 使用 Silverlight 消耗 WCF 服务涉及哪些步骤?
- 为什么我们不能直接在 Silverlight 中使用 ADO.NET?
- 我们如何使用 Silverlight 进行数据库操作?
- 其他 Silverlight 常见问题解答
- 历史
引言
本文讨论了 12 个关于绑定、布局、使用 WCF 服务以及如何通过 Silverlight 连接数据库的常见问题解答。文章从绑定开始,讨论了单向、双向和一次性绑定。然后,文章继续讨论了三种不同的 Silverlight 控件布局和定位方式。最后,文章将讨论如何在 Silverlight 中使用 WCF 服务以及如何进行数据库操作。
我收集了 WCF、WPF、WWF、SharePoint、设计模式、UML 等方面的约 400 个常见问题解答。欢迎从这里下载这些常见问题解答 PDF。
您能解释一下单向和双向绑定吗?
单向绑定
顾名思义。在单向绑定中,数据仅从对象流向 UI,反之则不然。例如,您可能有一个名为“TxtYear”的文本框,它绑定到一个具有“Year”属性的对象。因此,当对象值发生变化时,它会在 Silverlight UI 中得到反映,但 UI 无法更新对象中的“year”属性。
实现单向绑定需要三个步骤。首先,创建您想要与 Silverlight UI 绑定的类。例如,下面是一个简单的类,名为“ClsDate”,带有一个“Year”属性。
public class clsDate
{
private int _intYear;
public int Year
{
set
{
_intYear = value;
}
get
{
return _intYear;
}
}
}
第二步,您需要将“Year”属性与 Silverlight UI 文本框关联起来。要绑定属性,您需要在 `textbox` UI 对象的 `text` 属性中指定“Binding Path=Year”。“Year”是我们正在与 `textbox` UI 对象绑定的属性。
<TextBox x:Name="txtCurrentYear" Text="{Binding Path=Year}"
Height="30" Width="150" VerticalAlignment="Center" HorizontalAlignment="Center">
</TextBox>
最后一步是将 `textbox` 的数据上下文绑定到刚刚创建的日期对象。
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
clsDate objDate = new clsDate();
objDate.Year = DateTime.Now.Year;
txtCurrentYear.DataContext = objDate;
}
}
双向绑定
双向绑定确保 UI 和对象之间的数据同步。因此,对象中的任何更改都会反映到 UI 中,UI 中的任何更改都会反映到对象中。
要实现双向绑定,除了为“OneWay”提供的步骤外,还有两个额外的步骤。第一个更改是我们必须将模式指定为“TwoWay”,如下面的 XAML 代码片段所示。
<TextBox x:Name="txtEnterAge" Text="{Binding Path=Age, Mode=TwoWay}"
Height="30" Width="150" VerticalAlignment="Center" HorizontalAlignment="Center">
</TextBox>
第二个更改是我们必须实现“INotifyPropertyChanged”接口。下面是显示如何实现“INotifyPropertyChanged”接口的类。请注意,您需要导入“System.ComponentModel”命名空间。
public class clsDate : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int _intYear;
public int Year
{
set
{
_intYear = value;
OnPropertyChanged("Year");
}
get
{
return _intYear;
}
}
private void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this,new PropertyChangedEventArgs(property));
}
}}
数据与数据上下文的绑定是必须执行的步骤。
您能解释一下一次性绑定吗?
在一次性绑定中,数据仅从对象流向 UI 一次。没有跟踪机制来更新任何一方的数据。与前面讨论的两种绑定相比,一次性绑定在性能上有了显著的提高。对于数据仅加载一次并进行查看的报表,这种绑定是一个不错的选择。
<TextBox x:Name="txtEnterAge" Text="{Binding Path=Age, Mode=OneTime}"
Height="30" Width="150" VerticalAlignment="Center" HorizontalAlignment="Center">
</TextBox>
您能演示一个单向和双向绑定的简单示例吗?
下面是一个简单的示例代码,其中有两个文本框,一个用于输入年龄,另一个文本框用于计算近似出生日期。
下面是一个简单的类,它同时拥有这两个属性。我们实现了“INotifyPropertyChanged”接口,以便我们可以对 `year` 属性进行双向通信。
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
//
using System.ComponentModel;
namespace SilverLightBinding
{
public class clsDate : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int _intYear;
private int _intAge;
public int Year
{
set
{
_intYear = value;
OnPropertyChanged("Year");
}
get
{
return _intYear;
}
}
public int Age
{
set
{
_intAge = value;
Year = DateTime.Now.Year - _intAge;
}
get
{
return _intAge;
}
}
private void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this,
new PropertyChangedEventArgs(property));
}
}
}
}
最后,我们还实现了 SilverLight UI 对象与类属性的绑定。下面是相应的 XAML 片段。需要注意的一点是,“Age”是使用双向模式绑定的,因为我们需要从用户界面修改它。
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Center"> Enter your age in the below text box</TextBlock>
<TextBox x:Name="txtEnterAge" Text="{Binding Path=Age, Mode=TwoWay}"
Height="30" Width="150" VerticalAlignment="Center"
HorizontalAlignment="Center"></TextBox>
<TextBlock VerticalAlignment="Center"
HorizontalAlignment="Center">Your approximate birth date</TextBlock>
<TextBox x:Name="txtCurrentYear" Text="{Binding Path=Year}" Height="30"
Width="150" VerticalAlignment="Center"
HorizontalAlignment="Center"></TextBox>
您可以在本文末尾下载相应的源代码。
Silverlight 中提供了哪些不同的布局方式?
Silverlight 提供了三种布局管理方式:`Canvas`、`Grid` 和 `Stack` 面板。这些方法中的每一种都适合不同的布局需求。所有这些布局控件都继承自 `Panel` 类。在接下来的部分中,我们将逐一探讨它们,以了解它们的工作原理。
您能解释一下 Canvas 布局是如何工作的吗?
`Canvas` 是最简单的布局管理方法。它使用“X”和“Y”坐标支持绝对定位。“Canvas.Left”用于指定 X 坐标,而“Canvas.Top”用于提供“Y”坐标。
下面是一个简单的代码片段,显示了如何使用“Canvas”在坐标 (50, 150) 处定位一个矩形对象。
<Canvas x:Name="MyCanvas">
<Rectangle Fill="Blue" Width="100"
Height="100"
Canvas.Left="50"
Canvas.Top="150"/>
</Canvas>
显示效果如下。当您运行代码时,XAML 查看器会将矩形对象定位在绝对的“X”和“Y”坐标上。
如何实现 Grid 布局?
Grid 布局帮助您使用行和列来定位控件。它非常类似于 HTML 中定义的表格。
下面是一个使用“Grid”定义的具有两列两行的简单表格。我们展示了表格的显示效果。使用“Grid.ColumnDefinition”,我们定义了两列;使用“Grid.RowDefinition”,我们定义了两行。然后我们创建了 4 个文本块,并使用“Grid.Column”和“Grid.Row”在每个部分中指定它们。例如,要将文本块放在第一列,我们需要将“Grid.Column”指定为“0”,将“Grid.Row”指定为“0”。我们对所有文本块都遵循相同的模式,您可以看到所有 `textblock` 都放置在适当的部分。
如何实现 Stack 布局?
顾名思义。Stack 允许您垂直或水平排列 UI 元素。
例如,下面是堆叠在 StackPanel 元素中的四个元素。您可以看到 StackPanel 如何将元素一个接一个地对齐/堆叠。您还可以根据布局的性质水平或垂直堆叠 UI 元素。
您可以在本文末尾找到一个演示这三种布局的简单源代码。
使用 Silverlight 消耗 WCF 服务涉及哪些步骤?
消耗 WCF 服务需要四个步骤。
第一步:创建您的 WCF 服务
第一步是创建您的 WCF 服务。当我们创建 WCF 服务时,默认情况下它会创建一个“GetData”函数,该函数接受一个整数值并返回一个字符串,例如“You entered 10”,如果您将“10”作为值传递给函数。在接下来的步骤中,我们将尝试在 Silverlight 中使用此服务。
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
}
第二步:为您的 WCF 服务启用跨域
在本例中,我们的 WCF 服务和 Silverlight Web 应用程序将托管在不同的 IIS 网站上。换句话说,它们将托管在不同的域上。当我们谈论不同的网站时,换句话说,它们托管在不同的域上。例如,您的 Silverlight Web 应用程序可能托管在一个域上,如 www.xyz.com,而您的 WCF 服务托管在不同的域上,即 www.pqr.com。
WCF 服务需要启用跨域功能,以便其他域可以使用 WCF 服务。
我们需要在 WCF 服务的根目录中创建两个 XML 文件(clientaccesspolicy.xml 和 crossdomain.xml)来启用跨域功能。
下面是 `clientaccesspolicy.xml` 的 XML 代码片段。
<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource include-subpaths="true" path="/"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
下面是 `crossdomain.xml` 的 XML 代码片段。
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>
第三步:添加 WCF 服务引用并调用服务
创建一个简单的 Silverlight 应用程序,并将服务引用添加到您的 Silverlight 项目中。为了调用 WCF 服务,我们需要定义事件处理程序。使用 WCF 服务需要三个步骤。第一步,引用命名空间。第二步,创建 WCF 服务的对象。最后一步,我们需要创建一个事件处理程序,该处理程序将获取 WCF 服务发送的结果。
需要注意的一个重要点是,“GetData”函数是异步调用的。
第四步:添加 WCF 服务引用并调用服务
最后,编译程序并享受结果。
您可以在本文末尾获取此源代码。
为什么我们不能直接在 Silverlight 中使用 ADO.NET?
Silverlight 不包含 ADO.NET
下面是构成 Silverlight 插件的各种组件。需要注意的一个重要点是它不包含 ADO.NET。换句话说,您不能直接从 Silverlight 应用程序调用 ADO.NET 代码。现在要指出的另一点是,它包含 WCF 组件。换句话说,您可以调用 WCF 服务。
换句话说,您可以创建一个执行数据库操作的 WCF 服务,Silverlight 应用程序将调用该服务。另一点需要注意是不要返回数据集等 ADO.NET 对象,因为 Silverlight 将无法理解它们。
下面是我们在 Silverlight 中使用数据库 WCF 服务时需要遵循的七个重要步骤。
我们如何使用 Silverlight 进行数据库操作?
第一步:创建服务和数据服务合同
下面是一个简单的客户表,包含三个字段:“CustomerId”(自增列)、“CustomerCode”(存储客户代码)和“CustomerName”(存储客户姓名)。我们将使用 WCF 执行一个简单的 `select` 查询,然后将数据显示在 Silverlight 网格中。
字段 | 数据类型 |
CustomerId | int |
CustomerCode | nvarchar(50) |
CustomerName | nvarchar(50) |
根据上面指定的 `customer` 表,我们首先需要定义 WCF 数据合同。下面是 `customer` WCF 数据合同。
[DataContract]
public class clsCustomer
{
private string _strCustomer;
private string _strCustomerCode;
[DataMember]
public string Customer
{
get { return _strCustomer; }
set { _strCustomer = value; }
}
[DataMember]
public string CustomerCode
{
get { return _strCustomerCode; }
set { _strCustomerCode = value; }
}
}
我们还需要定义一个 WCF 服务合同,它将由 WCF 具体类实现。
[ServiceContract]
public interface IServiceCustomer
{
[OperationContract]
clsCustomer getCustomer(int intCustomer);
}
第二步:编写 WCF 服务代码
既然我们已经定义了数据合同和服务合同,现在是时候实现服务合同了。我们实现了“getCustomer”函数,该函数将返回“clsCustomer”`datacontract`。“getCustomer”函数建立了一个简单的 ADO.NET 连接,并使用“Select”SQL 查询检索 `customer` 信息。
public class ServiceCustomer : IServiceCustomer
{
public clsCustomer getCustomer(int intCustomer)
{
SqlConnection objConnection = new SqlConnection();
DataSet ObjDataset = new DataSet();
SqlDataAdapter objAdapater = new SqlDataAdapter();
SqlCommand objCommand = new SqlCommand
("Select * from Customer where CustomerId=" + intCustomer.ToString());
objConnection.ConnectionString =
System.Configuration.ConfigurationManager.ConnectionStrings["ConnStr"].ToString();
objConnection.Open();
objCommand.Connection = objConnection;
objAdapater.SelectCommand = objCommand;
objAdapater.Fill(ObjDataset);
clsCustomer objCustomer = new clsCustomer();
objCustomer.CustomerCode = ObjDataset.Tables[0].Rows[0][0].ToString();
objCustomer.Customer = ObjDataset.Tables[0].Rows[0][1].ToString();
objConnection.Close();
return objCustomer;
}
}
第三步:复制 CrossDomain.xml 和 ClientAccessPolicy.XML 文件
此 WCF 服务将从外部域调用,因此我们需要通过创建“CrossDomain.xml”和“ClientAccessPolicy.xml”来在 WCF 服务中启用跨域策略。下面是两个代码片段。第一个代码片段用于跨域,第二个用于客户端访问策略。
<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>
<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource include-subpaths="true" path="/"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
第四步:将 WCF 绑定更改为“basicHttpBinding”
Silverlight 仅支持并生成“basicHttpBinding”的代理,因此我们需要相应地更改终结点绑定。
<endpoint address="" binding="basicHttpBinding" contract="WCFDatabaseService.IServiceCustomer">
第五步:添加服务引用
我们需要使用“添加服务引用”菜单在 Silverlight 应用程序中使用服务引用。因此,右键单击 Silverlight 项目并选择“添加服务引用”。
第六步:定义客户姓名和客户代码的 Grid
现在在 Silverlight 端,我们将创建一个具有两列的“Grid”,一列用于“CustomerCode”,另一列用于“CustomerName”。我们还使用文本块中的“Binding path”指定了绑定。
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock x:Name="LblCustomerCode" Grid.Column="0"
Grid.Row="0" Text="Customer Code"></TextBlock>
<TextBlock x:Name="TxtCustomerCode" Grid.Column="1"
Grid.Row="0" Text="{Binding Path=CustomerCode}"></TextBlock>
<TextBlock x:Name="LblCustomerName" Grid.Column="0"
Grid.Row="1" Text="Customer Name"></TextBlock>
<TextBlock x:Name="TxtCustomerName" Grid.Column="1"
Grid.Row="1" Text="{Binding Path=Customer}"></TextBlock>
</Grid>
第七步:将 WCF 服务绑定到 GRID
现在我们的网格已创建,是时候将 WCF 服务绑定到网格了。因此,转到 XAML 文件的后端代码,并创建 WCF 服务对象。从 Silverlight 调用 WCF 服务时,有两点需要注意。
- 我们需要异步调用 WCF,因此我们调用了“getCustomerAsynch”。请注意,此函数是由 WCF 服务创建的,用于对方法/函数进行异步调用。
- 一旦函数在 WCF 服务上完成其工作,它会将消息发送回 Silverlight 客户端。因此,我们需要某种委托方法来促进这种通信。您可以看到我们创建了一个“getCustomerCompleted”方法,该方法捕获参数并将结果与网格的“datacontext”关联起来。
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
ServiceCustomerClient obj = new ServiceCustomerClient();
obj.getCustomerCompleted +=
new EventHandler<getCustomerCompletedEventArgs>(DisplayResults);
obj.getCustomerAsync(1);
}
void DisplayResults(object sender, getCustomerCompletedEventArgs e)
{
LayoutRoot.DataContext = e.Result;
}
}
现在您可以运行项目,看看 Silverlight 客户端如何使用和显示数据。
其他 Silverlight 常见问题解答
Silverlight 常见问题解答 第一部分
本教程包含 21 个基本常见问题解答,将帮助您理解 WPF、XAML,构建您的第一个 Silverlight 应用程序,并解释整体 Silverlight 架构。
SilverLight FAQ 第 2 部分(动画和变换)
本教程包含 10 个常见问题解答,从 Silverlight 动画基础知识开始,然后展示一个简单的动画矩形。然后,文章将进一步讨论对象的四种不同变换方式。
历史
- 2009 年 6 月 23 日:初始版本
如需进一步阅读,请观看以下面试准备视频和分步视频系列。