显示标签为“Silverlight”的博文。显示所有博文
显示标签为“Silverlight”的博文。显示所有博文

2010年2月10日星期三

WCF RIA 服务 (二十九)-- Silverlight 客户端 10

如何:在客户端添加计算特性
我们可以在客户端添加成员属性,这些属性是有实体类中的成员属性计算而来。局部方法被用来引发事件,来通知用户界面元素数值已被更改。当我们添加计算的成员属性时,这些属性只存在于客户端项目中。

1. 在客户端项目中,添加一个类文件。
2. 声明一个局部类,这个类与我们想要修改的实体代理类具有相同的名字和命名空间。
3. 添加一个属性,创建一个基于一个或多个实体代理类中值的新值。
4. 对每一个用于计算新值的成员属性都实施On[CustomProperty]Changed局部方法,并且调用RaisePropertyChanged方法来通知框架计算的属性已经更改。

下面的示例演示了如何为一个员工计算总的不工作的有效时间,这个时间是基于休假时间和生病请假的时间。对休假时间或生病请假的时间的改动,都将会对总时间产生一个改动。

using System.Windows.Ria;

namespace RIAServicesExample.Web
{
public partial class Employee : Entity
{
public int TotalOffHours
{
get { return this.SickLeaveHours + this.VacationHours; }
}
partial void OnSickLeaveHoursChanged()
{
this.RaisePropertyChanged("TotalOffHours");
}
partial void OnVacationHoursChanged()
{
this.RaisePropertyChanged("TotalOffHours");
}
}
}


可以用下面的代码来对计算的属性进行数据绑定:




WCF RIA 服务 (二十八)-- Silverlight 客户端 9

自定义生成代码
对于WCF RIA Services,在某些情况下,我们想在客户端生成的代码中添加些东西。然而,我们不能直接定制生成代码,因为在下次中间层重新编译的时候会被覆盖掉。RIA Services在生成代码中提供了局部方法,这样我们可以在分开的代码文件中定制客户端代码。这些局部方法就如同“钩子”,通过它我们可以把自己的代码附加在生成代码上。只有当我们已经创建了对应的局部方法时,这些方法才能被调用。
局部方法
WCF RIA Services框架为域上下文类和实体类生成局部方法。
对于域上下文类,提供了下面的局部方法。
OnCreated():当DomainContext对象实例化时执行。

对于实体类,提供了下面的局部方法。
OnCreated():当实体对象实例化时执行。

OnLoaded(boolean):在第一次装载实体并反串行化时,或当实体从服务端反串行化但已经在客户端存在时执行。

On[PropertyName]Changing: 在验证之后,设定值之前,被调用。

On[PropertyName]Changed: 在设定值之后,调用RaiseDataMemberChanged方法之前,被调用。

On[CustomMethodName]Invoking: 调用定制方法之后,实际执行代码之前,被调用。

On[CustomMethodName]Invoked: 定制方法调用并执行代码之后,被调用。

实施局部方法
要使用这些方法,我们添加一个与想定制的生成类相同名字和命名空间的局部类。应为自动生成的客户端代码与服务端项目的代码有一样的命名空间,所以我们局部类的命名空间通常是projectname.Web的格式。然后,在客户端代码必须执行的情况下,我们实施想要执行的方法。例如在一个域上下文被创建并装载时,我们添加如下代码:

using System.Windows.Ria;

namespace RIAServiceExample.Web
{
public partial class EmployeeDomainContext : DomainContext
{
partial void OnCreated()
{
this.Load(this.GetEmployeesQuery());
}
}
}


我们还可以在生成的实体类的局部方法中设置成员属性。例如,如果数据库中的员工表中包含一个名为CreatedBy字段,那么我们可以通过OnCreated()局部方法来设置这个属性的值。

using System.Windows.Ria;

namespace RIAServiceExample.Web
{
public partial class Employee : Entity
{
partial void OnCreated()
{
this.CreatedBy = WebContext.Current.User.Name;
}
}
}

2010年2月7日星期日

WCF RIA 服务 (二十七)-- Silverlight 客户端 8

演练:在Silverlight商业应用程序中显示数据
在本演示中,我们将创建一个显示数据的Silverlight商业应用程序。Visual Studio提供了几个设计时工具来帮助我们创建SL商业应用程序。这个演练将展现如何使用DataSources窗口在RIA中创建与数据一起工作的用户界面。
演示将会满足下面的任务:
1. 创建SL商业应用程序,它包含SL客户端和ASP.NET Web应用两个项目。
2. 通过更改应用程序名字来修改应用程序资源,它存贮为资源字符。
3. 创建一个AdventureWorksClassLibrary示例数据库的实体数据模型。
4. 创建一个向客户端公开实体数据模型中数据的域服务。
5. 在域服务中添加和修改自定义查询。
6. 创建额外的SL页面来向用户显示数据。
7. 在默认的导航栏中添加按钮来访问SL中的页面。
8. 通过从Data Sources窗口向Silverlight设计器中拖拽条目来配置SL页面显示数据。
9. 排序和分页数据。
10. 配置用户界面来接受查询参数。

这个演练是在VS2010中进行的,如果是其他版本会有不同。

创建SL商业应用程序

1. 打开文件->新建->项目
2. 展开Visual c#或Visual Basic,并选择Silverlight。
3. 选择Silverlight Business Application
4. 在名字文本框内,输入AdventureWorksApp并点击OK。
这个解决方案包含两个项目:一个AdventureWorksApp客户端项目和一个AdventureWorksApp.Web Web应用项目。

命名和测试应用程序
Silverlight Business Application有内置功能。默认的,它有一个主页,一个关于页,一个导航栏,以及注册功能。提供了一个资源字符来作为默认的应用程序名字,我们可以更改它。
1. 在客户端解决方案资源管理器中,展开Resources文件夹。(VS2008中打开Assets文件夹下的Resources文件夹)
2. 双击ApplicationStrings.resx,打开资源编辑器。
3. 把资源字符串ApplicationName的值改为Adventure Works Application.
4. 保存并关闭ApplicationStrings.resx文件。
5. 运行应用程序。
主页会打开并显示默认的设计,包括已经更改过的应用程序名称。

为应用程序创建一个数据模型

1. 在解决方案资源管理器中,右键点击AdventureWorksApp.Web,并添加一个新项。
2. 在"添加新项"对话框中,选择ADO.NET Entity Data Model项。
3. 命名为AdventureWorksEDM.edmx,然后点击添加。实体数据模型向导会打开。
4. 在"选择模型内容"的页面上,点击"从数据库生成",然后点击"下一步"。
5. 在"选择数据连接"的页面上,选择或创建对AdventureWorks数据库的链接。
6. 确保选择了"Save entity connection settings in Web.Config as"选项,然后点击"下一步"。
7. 在"选择数据库对象"的页面上,重新命名模型命名空间Model为AdventureWorksDataModel。
8. 展开"表"节点,选择Customer表。
9. 点击"完成"。
10. 生成解决方案。

创建域服务

一个域服务会把数据模型中的数据实体和操作公开给客户端。它是添加在服务端项目中的。
1. 在"解决方案资源管理器"中,右键点击AdventureWorksApp.Web,并添加一个新项。
2. 在"添加新项"对话框中,选择"Domain Service Class"。
3. 命名为AdventureWorksService。
4. 点击"添加"。 "添加新项"对话框出现。
5. 选择下面的复选框:
. Enable client access
. Customer 和 Enable editing
. Generate associated classes for metadata.
6. 点击OK
7. 生成解决方案。

更改域服务的查询

域服务提供默认的操作,我们应该为我们特定的应用而修改它们。这个演练中,我们更改默认的查询,来返回按CustomerID排序的客户。

1. 在"解决方案资源管理器"中,双击AdventureWorksSercice.cs或AdventureWorksService.vb.
2. 更改GetCustomers方法,如下:

public IQueryable GetCustomer()
{
return this.ObjectContext.Customer.OrderBy(c=>c.CustomerID);
}

3. 生成解决方案。

创建Silverlight页面来显示数据
从Customer表返回的数据显示在自己的页面上,不显示在应用程序的首页上。

1. 在"解决方案资源管理器"中,右键点击客户端项目中的Views文件夹,并添加新项。
2. 在"添加新项"对话框中,选择Silverlight Page项。
3. 更改名字为CustomerList.xaml,并点击"添加"。
4. 从工具栏拖拽一个TextBlock放在CustomerList.xaml页面的顶部。
5. 把Text属性改为Customer List。
6. 保存CustomerList.xaml页面。

在首页上添加导航按钮
我们在应用程序的首页上添加一个导航到CustomerList页面的按钮。

1. 在"解决方案资源管理器"中,双击MainPage.xaml.
2. 在XAML视图里,在行下面添加如下代码:



NavigateUri="/CustomerList" TargetName="ContentFrame"/>

3. 运行应用程序,确认Customers按钮显示在导航栏上,并点击的时候显示CustomerList页面。

在CustomerList页面上显示客户数据
在DataGrid中显示客户数据。下面,我们就创建和配置一个DataGrid来显示客户数据,需要从Data Sources窗口拖拽一个Customer实体到设计窗口内。

1. 双击CustomerList.xaml。
2. 打开Data Sources窗口。可以在Data菜单中,选择Show Data Sources。注意Data Sources窗口已经包含了可用的实体。
3. 从Data Sources窗口中把Customer节点拖到设计器中,在TextBlock下面。
4. 运行应用程序并点击导航栏上的Customers按钮。
5. 核实在CustomerList页面上显示了Customer数据。
(我在VS2008中使用Data source有问题,生成不了数据节点。好像在Silverlight3中没有了ComponentModel.dll,所以直接使用域上下文来查询数据)

在域服务中添加自定义查询

1. 双击AdventureWorksService.cs。
2. 在类中添加如下代码:

public IQueryable GetCustomersByTitle()
{
return this.ObjectContext.Customer.Where(c => c.Title == "Mr.").OrderBy(c => c.CustomerID);
}

public IQueryable GetCustomersByLastName(string lastName)
{
return this.ObjectContext.Customer.Where(c => c.LastName==lastName).OrderBy(c=>c.CustomerID);
}

3. 生成解决方案。

显示自定义查询返回的数据

1. 双击CustomerList.xaml。
2. 在"数据源"窗口,选择Customer并点击下拉菜单。
3. 在查询列表中选择GetCustomersByTitle。
4. 把Customer节点拖拽到已经存在于设计器中的DataGrid。
5. 运行应用程序,并验证只有Title等于Mr.的顾客显示在页面上。

添加排序功能

VS2008中实现如下:
1. 双击CustomerList.xaml。
2. 在XAML视图中,在DomainDataSource控件中,添加SortDescriptors。
3. 设置PropertyPath属性为"LastName"。设置Direction属性为Ascending。
4. 运行应用程序,注意到顾客数据已经按LastName排序了。

添加分页功能

VS2008中实现如下:
1. 双击CustomerList.xaml。
2. 在XAML视图中,在DomainDataSource控件中,添加PageSize属性,并设置为15.添加LoadSize属性,并设置为30.
3. 添加DataPager控件。



4. 运行应用程序,注意到页面装载的速度已经大大加快了。并且可以通过DataPager控件浏览数据。

创建一个页面来根据LastName进行查询

1. 在AdventureWorksApp中的Views文件夹下,添加新项。
2. 在"添加新项"对话框中,选择Silverlight Page项。
3. 命名为CustomerSearchByLastName.xaml,并点击"添加"。
4. 保存这个页面。

在首页中添加一个导航按钮

1. 双击MainPage.xaml。
2. 在XAML视图中,在Link3的HyperlinkButton下面添加如下代码。






创建用户界面来运行GetCustomerByLastName查询
VS2008中实现如下:

1. 双击CustomerSearchByLastName.xaml
2. 添加命名空间引用

xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Ria"
xmlns:riaData="clr-namespace:System.Windows.Data;assembly=System.Windows.Controls.Ria"
xmlns:domain ="clr-namespace:AdventureWorksApp.Web"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

3. 然后在Grid中添加数据源、DataGrid、文本框和按钮(实际代码中不需SL:前缀),如下代码:






















测试应用程序

1. 生成解决方案。
2. 运行应用程序。
3. 点击"Customer Search"。
4. 在文本框中输入想要查询的LastName,例如"liu"。
5. 点击Load按钮。
6. 将会显示名为"liu"的客户。

WCF RIA 服务 (二十六)-- Silverlight 客户端 7

演练:编辑来自域服务的数据
当我们在域服务中添加了更新、插入或删除方法时,我们就可以在Silverlight客户端创建一个接口来让用火修改数据。EntityChangesSet对象跟踪所有的改变,并且这些改变在我们调用SubmitChanges方法时一起提交。
在这个演练中,我们将学习如何创建一个让用户修改所显示数据的接口,并且将这些修改保存到数据库。

演练

1. 打开RIAServicesExample项目。(参见 WCF RIA 服务 三)
2. 在MainPage.xaml中,更改界面让用户可以保存或拒绝DataGrid中的更改。下面的XAML添加了一个Save Changes按钮和Reject Changes按钮,以及一个更改文本框。















3. 在MainPage.xaml的后台代码文件中,添加按钮的点击事件处理方法、RowEditEnded事件的处理方法、一个名为OnSubmitCompleted的回调方法,和一个处理行将发生的更改的方法。

private void SaveButton_Click(object sender, RoutedEventArgs e)
{
_customerContext.SubmitChanges(OnSubmitCompleted, null);
}

private void RejectButton_Click(object sender, RoutedEventArgs e)
{
_customerContext.RejectChanges();
CheckChanges();
}

private void CustomerGrid_RowEditEnded(object sender, DataGridRowEditEndedEventArgs e)
{
CheckChanges();
}

private void CheckChanges()
{
EntityChangeSet changeSet = _customerContext.EntityContainer.GetChanges();
ChangeText.Text = changeSet.ToString();

bool hasChanges = _customerContext.HasChanges;
SaveButton.IsEnabled = hasChanges;
RejectButton.IsEnabled = hasChanges;
}

private void OnSubmitCompleted(SubmitOperation so)
{
if (so.HasError)
{
MessageBox.Show(string.Format("Submit Failed: {0}", so.Error.Message));
so.MarkErrorAsHandled();
}
CheckChanges();
}


为要更改的实体设置元数据

1. 在服务端项目中,为Customer实体手动添加一个名为Customer.metadata.cs的元数据类。
2. 在元数据类中,对CustomerID和ModifiedData成员属性添加EditableAttribute属性并设置AllowEdit属性为false。我们对成员属性应用EditableAttribute来指定是否想让这个成员属性在客户端让用户编辑。当我们将AllowEdit为false时,这个成员属性在客户端是只读的。在这个例子中,我们只想显示CustomeId和ModifiedDate成员属性而不想用户修改它们。
3. 添加ExcludeAttribute属性给PasswordHash,PasswordSalt和rowguid成员属性。我们对不想包含客户端生成代码中的成员属性使用ExcludeAttribute。在这个例子中,我们没有必要把PasswordHash,PasswordSalt和rowguid成员属性向客户端公开。

[MetadataTypeAttribute(typeof(Customer.CustomerMetadata))]
public partial class Customer
{
internal sealed class CustomerMetadata
{

// Metadata classes are not meant to be instantiated.
private CustomerMetadata()
{
}

[Editable(false)]
public int CustomerID;

[Editable(false)]
public DateTime ModifiedDate;

[Exclude]
public string PasswordHash;

[Exclude]
public string PasswordSalt;

[Exclude]
public Guid rowguid;

}
}

4. 用using添加所需的命名空间,例如 System.ComponentModel.DataAnnotations和System.Web.DomainServices.
5. 运行应用程序。
注意我们可以在DataGrid中编辑值了。当我们离开所编辑的行时,ChangeText的值将会变为行将发生的更改的描述。当我们点击Save Changes按钮时,数据更改将会保存到数据库中。当点击Reject Changes按钮时,所有的行将发生的更改将恢复原样。

WCF RIA 服务 (二十五)-- Silverlight 客户端 6

演练:检索和显示来自域服务的数据
想要在Silverlight应用程序中检索数据,我们调用域上下文中的方法,这些方法对应着域服务中我们想要使用的查询方法。例如,在域服务中有个名为GetProducts的方法,那么在与上下文中有个名为GetProductsQuery的方法。在SL应用程序中,我们调用GetProductsQuery方法,此方法返回一个EntityQuery(TEntity)对象。
在SL应用程序中,我们可以对查询应用额外的过滤来限制返回的实体。虽然一个查询方法可以返回产品表的所有记录,但可能我们只想显示价格低于100的产品。我们使用LINQ和LINQ运算符的子集来改变从查询返回的结果。下面列出了可用的查询运算符:
1. Where
2. OrderBy
3. ThenBy
4. Skip
5. Take
当应用了额外的过滤时,我们把EntityQuery(TEntity)对象传递给Load方法的一个参数,来运行查询和得到结果。如果查询有一个IsComposable属性设为false的QueryAttribute([Query(IsComposable = false)])。我们不可以在查询上应用额外的过滤。通常,只有返回单一实体的查询把IsComposable设置为false。
我们可以把数据绑定到任何显示数据的SL控件。DataGrid控件可以以表格的格式来显示数据。

演练
1. 打开RIAServicesExample解决方案。(WCF RIA 服务 三
2. 在Silverlight应用程序中,打开MainPage.xaml的代码文件。
3. 调用GetCustomersQuery方法来创建EntityQuery(TEntity)实例。
4. 使用可用的查询运算符来过滤客户。
5. 把查询对象传递给DomainContext的Load方法,并报返回结果赋给LoadOperation(TEntity).
下面的代码演示如何从域服务检索客户信息。并且过滤电话号码以583开始的客户,同时以LastName按字母排序。结果显示在DataGrid控件中。

public partial class MainPage : UserControl
{
private CustomerDomainContext _customerContext = new CustomerDomainContext();

public MainPage()
{
InitializeComponent();
EntityQuery query =
from c in _customerContext.GetCustomersQuery()
where c.Phone.StartsWith("583")
orderby c.LastName
select c;
LoadOperation loadOp = this._customerContext.Load(query);
CustomerGrid.ItemsSource = loadOp.Entities;
}
}

结果显示如下:

2010年2月6日星期六

WCF RIA 服务 (二十四)-- Silverlight 客户端 5

在客户端处理错误
当我们在客户端检索或修改数据时,我们通常需要处理错误和对错误做出反应。通过WCF RIA Services,我们为数据操作提供一个回调方法来处理错误,并且在回调方法里检查错误。使用回调方法是必需的,因为调用数据操作都是异步的,比且异常也是异步抛出的。默认下,对域操作中的所有错误都抛出一个异常。RIA Services为我们提供了处理错误的方式,并且可以指定框架不抛出异常。

当装载数据时处理错误
当从一个查询装载数据时,我们可以选择处理错误或忽略之。明确地,我们从如下选项中选择:

1. 使用带有回调方法做为参数的Load方法。在回调方法内,处理错误,并调用MarkErrorAsHandled方法来指定不要抛出错误。

2. 使用带一个名为thowOnError的Boolean参数的Load方法。当调用Load方法时,设置throwOnError为false来指定我们不想为查询错误抛出异常。

3. 当Load方法没有回调参数和布尔参数时,任何查询错误都会导致一个未处理的异常。
下面的示例演示了如何从查询载入数据,并指定一个回调方法来检测装载操作中的错误。

private CustomerDomainContext _customerContext = new CustomerDomainContext();

public MainPage()
{
InitializeComponent();

LoadOperation loadOp = this._customerContext.Load(this._customerContext.GetCustomersQuery(), OnLoadCompleted, null);
CustomerGrid.ItemsSource = loadOp.Entities;
}

private void OnLoadCompleted(LoadOperation lo)
{
if (lo.HasError)
{
MessageBox.Show(string.Format("Retrieving data failed: {0}", lo.Error.Message));
lo.MarkErrorAsHandled();
}
}


提交数据时处理错误
当提交数据时,我们不能像Load方法那样选择关闭异常。所有提交数据时发生的错误都会导致一个异常。明确地,我们可以选择如下选项:

1. 使用带回调参数的SubmitChanges方法。在回调方法里,处理错误并调用MarkErrorAsHandled方法来指定不要抛出异常。

2. 使用SubmitChanges方法,所有在提交数据时发生的错误都导致一个异常。

下面的示例演示了如何调用带有回调参数的SubmitChanges方法。

private void SaveButton_Click(object sender, RoutedEventArgs e)
{
_customerContext.SubmitChanges(OnSubmitCompleted, null);
}

private void RejectButton_Click(object sender, RoutedEventArgs e)
{
_customerContext.RejectChanges();
CheckChanges();
}

private void CustomerGrid_RowEditEnded(object sender, DataGridRowEditEndedEventArgs e)
{
CheckChanges();
}

private void CheckChanges()
{
EntityChangeSet changeSet = _customerContext.EntityContainer.GetChanges();
ChangeText.Text = changeSet.ToString();

bool hasChanges = _customerContext.HasChanges;
SaveButton.IsEnabled = hasChanges;
RejectButton.IsEnabled = hasChanges;
}

private void OnSubmitCompleted(SubmitOperation so)
{
if (so.HasError)
{
MessageBox.Show(string.Format("Submit Failed: {0}", so.Error.Message));
so.MarkErrorAsHandled();
}
CheckChanges();
}


调用操作时处理错误
当调用一个操作时,我们有像提交数据时一样的选择。如下:

1. 当调用操作时包含一个回调参数。在回调参数内处理错误,并调用MarkErrorAsHandled方法来指定不要抛出异常。

2. 调用不包含回调参数的操作。所有在调用操作时发生的错误都会抛出异常。


InvokeOperation invokeOp = customerContext.GetLocalTemperature(selectedPostalCode, OnInvokeCompleted, null);

private void OnInvokeCompleted(InvokeOperation invOp)
{
if (invOp.HasError)
{
MessageBox.Show(string.Format("Method Failed: {0}", invOp.Error.Message));
invOp.MarkErrorAsHandled();
}
else
{
result = invokeOp.Value;
}
}


验证服务处理错误
AuthenticationService类允许我们在调用下面的方法时提供回调参数:
1.LoadUser 2.Login 3.Logout 4.SaveUser
在回调方法中,我们可以提供代码来处置从验证服务中来的错误。 下面的例子演示如何从登陆按钮的事件处理中调用Login方法。

private void LoginButton_Click(object sender, RoutedEventArgs e)
{
LoginParameters lp = new LoginParameters(UserName.Text, Password.Password);
WebContext.Current.Authentication.Login(lp, this.LoginOperation_Completed, null);
LoginButton.IsEnabled = false;
LoginResult.Text = "";
}

private void LoginOperation_Completed(LoginOperation lo)
{
if (lo.HasError)
{
LoginResult.Text = lo.Error.Message;
LoginResult.Visibility = System.Windows.Visibility.Visible;
lo.MarkErrorAsHandled();
}
else if (lo.LoginSuccess == false)
{
LoginResult.Text = "Login failed. Please check user name and password.";
LoginResult.Visibility = System.Windows.Visibility.Visible;
}
else if (lo.LoginSuccess == true)
{
SetControlVisibility(true);
}
LoginButton.IsEnabled = true;
}

2010年2月5日星期五

WCF RIA 服务 (二十三)-- Silverlight 客户端 4

DomainDataSource
WCF RIA Services提供DomainDataSource控件来简化用户界面和域上下文中数据的交互。通过DomainDataSource,我们可以只是用声明性语法来检索、编辑数据。我们指定域上下文与DomainDataSource一起使用,然后通过这个上下文来调用操作。
配置Silverlight应用程序的DomainDataSource
为了使用DomainDataSource控件,我们必须在包含DomainDataSource的SL控件中添加一个程序集的引用和命名空间。
在SL项目中,我们必须添加一个对System.Windows.Controls.Ria程序集的引用。如果选择DataGrid与DomainDataSource一起使用,我们还要添加对System.Windows.Controls.Data的引用。
在宿主控件内,例如UserControl,我们必须添加下面的命名空间引用:

xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Ria"
xmlns:riaData="clr-namespace:System.Windows.Data;assembly=System.Windows.Controls.Ria"
xmlns:domain="clr-namespace:SilverlightApplication17.Web"

如果选择使用DataGrid控件,还需添加下面的命名空间:

xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"

检索和显示数据
我们为DomainDataSource指定一个域上下文,并向用户提供方法的名字来装载数据。然后我们绑定表示控件,例如DataGrid对DomainDataSource。下面的例子演示了DomainDataSource检索从名为ProductDomainContext的域上下文而来的数据。在域服务中应该存在一个名为GetProduct()的查询方法。

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:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Ria"
xmlns:riaData="clr-namespace:System.Windows.Data;assembly=System.Windows.Controls.Ria"
xmlns:domain="clr-namespace:SilverlightApplication17.Web"
xmlns:datac="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
mc:Ignorable="d">













对查询添加参数
某些情况下,查询方法需要参数值。通常,一个查询方法需要一个参数值来过滤返回的数据。下面的示例演示如何添加参数值,这个值可通过声明性文本来指定。













还可以使用来自用户的值来为查询添加参数。我们使用ControlParameter对象来把来自用户输入控件的值传递到查询。下面的例子展示了如何指定来自下拉菜单中的值做为参数值。











ParameterName="color"
ControlName="colorCombo"
PropertyName="SelectedItem.Content"
RefreshEventName="SelectionChanged" />









排序
DomainDataSource提供SortDescriptors集合来简化数据的排序。在SortDescriptors集合中,我们提供SortDescriptor实例来向用户描述参数值。我们可以添加多个SortDescriptor实例。还可以指定数据排序的升降序。下面的示例演示DomainDataSource中的排序描述符,从查询中检索的数据按来自StandardPrice属性中的值排序。













分组
DomainDataSource提供了GroupDescriptors集合来通过属性值来简化分组数据。在GroupDescriptors集合中,我们提供GroupDescriptor示例来定义用来分组的值。可以添加多个GroupDescriptors实例。













过滤
DomainDataSource控件提供FilterDescriptors集合来允许我们过滤查询返回的数据。通过添加过滤,我们可以指定只装载满足条件的域上下文实体。在FIlterDescriptorCollection对象上设置LogicalOperator属性,我们可以在不同的过滤之间定义逻辑关系。
过滤描述符通过FilterOperator枚举器来支持操作。
当定义基于用户输入的过滤时,我们可以提供ControlParameter实例。下面的示例演示了两个通过逻辑AND连接的过滤描述符。一个过滤依赖于用户的输入,另一个过滤通过声明性语句来指定。














ControlName="MaxPrice"
PropertyName="SelectedItem.Content"
RefreshEventName="SelectionChanged" />












分页
当显示大量实体的时候,我们会希望在用户界面上提供分页功能。DomainDataSource控件允许我们指定在一个页面上装载和显现的实体数量。新纪录只有在用户导航到了还没有装载实体的页面时才装载。我们设置PageSize和LoadSize属性来指定分页的参数。然后,我们把一个DataPage实例绑定到DomainDataSource来实施分页的接口。
注意:如果在应用程序中DataPager与实体框架数据存贮一起使用,我们必须对为DataPager从查询返回的数据进行排序。因为实体框架不支持没有OrderBy子句或在SL客户端没指定排序的分页。


















编辑
进行数据更改,需要调用DomainDataSource对象的SubmitChanges方法。要取消更改,调用RejectChanges方法。

WCF RIA 服务 (二十二)-- Silverlight 客户端 3

DomainContext
从客户端项目内部,我们不直接与域服务交互。相反,会对服务端中的每个域服务在客户端生成一个域上下文类。我们在域上下文类上调用对应于域服务上想使用的方法。这个生成的域上下文类派生于DomainContext类。
查询
域上下文中的查询方法通常与域服务中的查询方法有相同的名字,并有后缀Query。例如,一个域上下文中的GetCustomersQuery方法生成于域服务中的GetCustomers方法。这个查询方法返回一个EntityQuery对象,我们可以在其他操作中应用这个对象。
域上下文中的所有查询方法都是异步执行的。为了执行这个查询,我们在Load方法中把EntityQuery对象作为参数传递。
修改数据
当域服务中包含更新、插入、删除实体的方法时,在域上下文中不会生成这些方法。反之,我们在与上下文中使用SubmitChanges方法,会调用域服务中的正确操作。直到我们调用SubmitChanges时,才会在数据源中进行更改。可以通过调用RejectChanges方法来取消更改。
DomainContext类还提供HasChanges和EntityContainer属性来允许我们评估行将发生的更改。对Domain context的EntityContainer对象跟踪行将发生的更改。行将发生的更改不包括对域服务中的操作的调用,因为这些操作会在被调用时立即执行。当调用SubmitChanges时,所有的行将发生的更改都一起发到域服务。
定制方法
对域服务中的那些有公共访问修饰符而且没有标记着IgnoreOperationAttribute属性的自定义方法,域上下文都会包含这些方法。域上下文中的这些方法的名字与域服务中的方法名字一样。在客户端,我们调用一个方法,直到SubmitChanges被调用时,这个方法才会被实际执行。EntityContainer会将所有对自定义方法的调用作为行将发生的更改来跟踪。当调用SubmitChanges时,方法是异步处理的。
在客户端项目中对实体也会生成同样的自定义方法,这些实体在自定义方法中做为参数传递。因此,可以通过一个域上下文的实例或实体的实例来调用定制的方法。如果打开生成的代码文件,会注意到域上下文中生成的方法只是简单的调用实体内的生成方法。在这两种情况下,我们还是需要调用Submitchanges方法来执行这些方法。
下面的示例演示如何调用一个名为ResetPassword的自定义方法,OnSubmitCompleted是我们想实施处理数据操作结果的回调函数。

selectedCustomer.ResetPassword();
customerContext.SubmitChanges(OnSubmitCompleted, null);

Invoke Operations 调用操作
对域服务上的每个服务操作,域上下文都包含一个方法。与域操作不同,服务操作都会立即执行。不用调用SubmitChanges方法,服务操作会异步执行。服务操作返回一个InvokeOperation对象。我们检索Value属性的值来得到从服务操作中返回的结果。
下面的示例演示了如果调用一个名为GetLocalTemperature的服务操作。

InvokeOperation invokeOp = customerContext.GetLocalTemperature(selectedPostalCode, OnInvokeCompleted, null);

private void OnInvokeCompleted(InvokeOperation invOp)
{
if (invOp.HasError)
{
MessageBox.Show(string.Format("Method Failed: {0}", invOp.Error.Message));
invOp.MarkErrorAsHandled();
}
else
{
result = invokeOp.Value;
}
}

处理错误
当我们检索或修改数据时,我们必须决定如果处理在这些操作中可能出现的错误。当我们在域上下文上调用检索或修改数据的方法时,我们包含了指定处理错误的步骤的参数。当装载数据时,我们可以指定忽略错误。但在修改数据时,我们必须处理返回的异常。更多详情,请看Silverlight 客户端 5.

WCF RIA 服务 (二十一)-- Silverlight 客户端 2

客户端代码生成
当我们使用RIA Services连接中间层和表示层时,RIA Services为客户端项目生成了客户端代理类,这些类是以中间层公开的实体和操作为基础的。因为RIA Services生成了这些类,所以我们不必再复制这些中间层和表示层中的应用逻辑。因为我们对中间层所做的任何修改,在重新生成客户端项目时都会自动与表示层同步的。

生成的代码位于客户端项目的Generated_Code文件夹内。想要看到这个文件夹,必须在客户端项目的解决方案资源管理器的窗口下,选择“显示所有文件”。我们不应直接改动此文件夹内的类,因为在客户端项目重新生成时,文件会被覆盖。然而,我们可以打开生成的文件,查看里面可被客户端项目利用的代码。


生成客户端代码的算法遵循以下规则:

1. 分析所有的程序集,包括生成的,或中间层为Domain service classes,Entity classes,shared code所引用的。

2. 对每个带有EnableClientAccessAttribute属性注释的域服务,都生成一个从DomainContext类派生的类。

3. 对每个域服务类中的查询方法、命名的更新方法或调用的操作,都在域上下文类中生成一个方法。

4. 对每个域服务公开的实体类,生成一个实体代理类。

5. 拷贝标记为共享的代码到客户端项目。

下图显示了一个中间层项目生成的客户端代码


DomainService 和 DomainContext

为每个域服务生成的派生于Domaincontext的类,遵循下面的规则:

1. Domain Context类须与Domain service具有一样的命名空间。

2. domain context类包含3个构造函数:

a. 默认的构造函数,嵌入了必要的URI,使用WebDomainClient(TContract)类在http上与域服务沟通

b. 允许用户指定一个可交替的URI的构造函数。

c. 允许用户提供一个自定义实现的DomainClient的构造函数。

3. 对每个与服务类中的查询方法,在domain context中都会生成一个EntityQuery(TEntity)方法。

4. 对每个命名的更新方法(named update method)或调用的操作,在域上下文中都会生成对应的方法。

5. 在domain service中执行插入、更新、删除的公共方法,会使域上下文中的EntityContainer在生成时带有EntitySetOperations标记,这个标记指定哪个操作在客户端是允许的。

实体类和实体代理类

生成实体代理类时,应遵循如下规则:

1. 代理类应该与中间层中的实体类具有一样的名字和命名空间。

2. 实体类中所有公共成员属性都会在代理类中生成,除非某些类型或成员属性已经在客户端项目中存在。

3. 每个属性设置器都包含执行验证和通知客户属性正在改变和已经改变的代码。

4. 元数据属性是与生成的代码中的实体类连在一起的。客户端不会存在元数据类。

5. 如果可能,定制的属性会传递到代理类。详情参阅下面的内容

定制的属性

如果定制的属性在客户端项目的编译中没有出现错误,那么这个定制的属性就可以传递到代理类中。为了保证属性能被传递,应满足如下条件:

1. 在客户端提供定制的属性的类型。

2. 在定制属性中指定的所有类型,在客户端都应该提供。

3. 这个定制属性必须对它所有的成员属性公开公共设置器,或者公开一个可以设置那些没有公共设置器的成员属性的构造函数。

如果所需的定制属性没有传递到客户端,我们可能需要在客户端中添加一个程序集引用。

共享代码

当在中间层和表示层之间共享代码时,代码被原封不动的拷到客户端项目中。通过命名文件为*.shared.cs来共享文件。

避免成员重复

当生成实体代理类时,有可能在客户端项目中已经定义了相同的类型和成员。我们可能已经在共享代码或只存在于客户端项目中的代码中定义了成员。RIA Service会在生成代理类之前检查已经存在的成员。所有已经存在的成员都不在代理类中生成。

WCF RIA 服务 (二十)-- Silverlight 客户端

Silverlight客户端
使用WCF RIA Services,我们可以创建一个当数据交互时知道中间层应用逻辑的Silverlight客户端。还可以对可见的和可编辑的数据提供用户接口,来在提交数据修改之前应用验证规则。我们的SL控件将会使用从中间层代码自动生成类。次章节介绍SL客户端如何使用domain context, 如何与数据一起工作,以及如何自定义生成的代码.
使用DomainContext
在中间层项目中会对每个domain service都生成一个DomainContext类来公开实体对象。在域上下文中包含着查询和修改等方法,这些方法与在域服务中对应的域操作进行沟通。当我们在SL应用程序中调用域上下文类上的一个查询方法时,这个查询方法会调用返回所需数据的域服务上的对应方法。这些域上下文上的方法都是异步执行的,所以在装载数据的时候,用户界面不会被锁定。
呈现和修改数据
我们使用SL控件,例如DataGrid控件,来呈现通过域上下文检索到的数据。我们把控件和查询结果绑定在一起。
我们也可以通过SL控件更新、插入和修改数据,当这些操作在域服务中公开时。当我们调用域服务上的数据修改操作时,中间层逻辑会处理来自SL客户端的数据,以确保商业规则应用到了修改操作上。
我们还可以使用DomainDataSource控件与来自域服务的数据交互。DomainDataSource控件允许我们使用声明语法来指定分页、排序、分组、和过滤数据。
自定义生成的代码
要想自定义生成的代码,我们不应该修改Generated_Code文件夹下的文件。因为当客户端项目重新生成时,这些文件将会被覆盖。反之,通过提供在域上下文中的局部方法和实体代理类,RIA Services允许我们为客户端自定义生成的代码。通过这些局部方法,我们可以在客户端添加计算性能,或添加当特定动作执行时需要的自定义逻辑。只有在我们已经实施了局部方法的情况下,生成的局部方法在会在运行时被调用。

2010年1月15日星期五

WCF RIA 服务 (二)- 解决方案结构

上节大概介绍了一下 WCF RIA 服务, 这次介绍下整个解决方案的结构。

当创建应用程序时,WCF RIA服务可以帮你建立满足各种各样情况的解决方案。例如只是在中间层访问很少domain services的Silverlight应用程序。更复杂的例子可能是几个Silverlight程序都连接到一个提供许多domain services的通用中间层。本节就介绍几种构建RIA服务解决方案的方式。

RIA 服务连接

在所有的RIA Services方案中,一个连接(就是RIA服务连接)存在于中间层项目和表示层项目之间。一个RIA Services连接是一个项目对项目引用的特殊模式,它更便于从中间层的代码来生成表现层的代码。在创建解决方案时选择 Enable WCF RIA Services 选项,就可以建立RIA Services 连接了。你也可以在已有项目的属性中建立RIA Services link。有的时候建立的连接是在应用项目之间的,而有些时候是建立在类库项目之间的。

当在项目中存在link时,表示层将会收到中间层的所有代码。不能指定只有一部分的代码应用到表示层。下面的规则用于RIA Services Link:
  • 在Silverlight的客户端项目中定义link。
  • link总是由Silverlight客户端指向.NET 服务端或类库。
  • 一个Silverlight客户端只能有一个link。
  • 这个link不能指向其他Sliverlight客户端。
  • 多个Silverlight客户端可以指向同一个服务端或类库。
  • 一个Silverlight应用程序不能连接到一个类库项目。

默认的解决方案结构

在默认的解决方案结构中,RIA Services创建一个单一的客户端项目和一个服务端项目。当使用Silverlight Application模板并勾选 Enable WCF RIA Services来创建项目时,就建立了一个默认的结构。一个RIA Services Link就已经在两个项目中存在了。当你生成解决方案时,将生成相对Domain Services和共享代码的客户端代码。下面的图展示了默认结构:

这个默认的结构是很方便的,因为所有的domain services类型和共享代码都在生成解决方案后自动添加到服务端和客户端。而且添加在服务端的共享代码,在客户端也是可见的。当你没有很多的domain services在服务端并且你也不必在很多不同的SL应用程序中重用商业逻辑时,默认的结构就已经可以很好的工作了。

在默认的解决方案结构中,你可以给服务端项目添加更多的具有RIA Services Link的SL应用程序。然而,默认的结构也存在局限性。对每一个SL客户端生成的代码包含所有来自服务端的中间层代码。例如,如果你有3个连接到一个服务端的SL应用程序,并且你想添加一个只能被其中一个SL应用程序使用的domain service,那么这3个客户端应用程序都将拥有为这个domain service生成的domain上下文并且可以访问这个domain service.

Silverlight Business Application template

RIA Services还提供了一个 Silverlight Business Application 模板。这个模板对建立一个SL商业应用程序提供了一个方便的出发点。这个模板建立在SL导航应用程序上,并用RIA Services来支持身份认证和用户注册。当用SL商业应用程序模板创建项目时,RIA Services建立默认的结构,并自动添加下面的特性:

  • 登录窗口
  • 注册窗口
  • SL导航
支持N层类库组件(Class Library Components)

RIA Services提供WCF RIA Services Class Library 项目类型来支持库中共享代码。通过类库,你把商业逻辑打包在N层类库组件里。下图展示使用RIA Services类库的解决方案结构:





在上图中,注意RIA Services Links并没存在于应用程序之中。相反,存在于类库项目中。你可以在你的应用程序中使用任意多的类库,并可以在任意的应用程序中重用这些类库。


使用RIA Services 类库有如下好处:

  • 服务端和一个单一数据域的客户端可以被作为一个单一的组件来开发和打包。这个组件可以在多个应用程序用重用。

  • 客户端的代理代码生成和源码共享都发生在一个位置。这个位置在每个组件的层中而不在每个SL应用程序中。

  • 在一个单一的Web应用程序中的多个SL应用可以指向它们所需的那个类库。每个SL应用程序不用再不得不看到中间层所公开的商业逻辑。

用RIA Services 类库,你可以仅提供应用程序所需的组件来建立灵活的解决方案结构。下图展示了一个应用多个RIA Services类库的方案结构:

WCF RIA 服务 (一)简介

WCF RIA Services简化了N层结构的RIA应用程序的开发,例如Silverlight应用。当开发一个N层结构的RIA应用程序时,一个通常的问题就是在中间层和表现层之间协调应用逻辑。为了建立更好的用户体验,你可能想要你的RIA客户端了解在服务器上的应用逻辑,但并不想开发和维护在表现层和中间层上的应用逻辑。现在RIA服务可以解决这个问题,它提供框架组件、工具以及服务来使RIA客户端不用手动复制程序逻辑就能调用位于服务器上的应用逻辑。你所建立的RIA客户端不仅能够了解商业逻辑,而且当每次解决方案编译时会自动更新中间层逻辑。


下图显示了一个简单的N层应用程序。RIA服务集中于在表现层和数据访问层之间的盒子内,目的是使n层结构的RIA客户端开发更简单。















RIA服务在Visual Studio中添加工具,使用这些工具能够在一个解决方案中把客户端和服务器端的项目连接起来,并且从中间层的代码中为客户端的项目生成代码。这些组件支持编写应用逻辑的规范模式,所以它能够在表现层中重复使用。提供适于通用情况的服务可以减少开发时间,例如身份验证和用户设置等。
可以从RIA服务站点来下载WCF RIA Services,现在提供两个版本:
  • WCF RIA Services Beta for Visual Studio 2008 SP1
  • WCF RIA Services Preview for Visual Studio 2010

在RIA Services中,通过添加域服务(domain services)来向客户端项目公开服务器项目的数据。RIA服务框架引用的域服务就是调用WCF服务。因此,当自定义配置时,可以使用从WCF服务中得到的概念来应用到域服务中。

2010年1月14日星期四

Silverlight 导航概述 2

外部导航

应用程序可以提供指向其他网页的直接链接。外部导航可用于提供对应用程序外部资源的访问。还可以将外部导航用于 Silverlight 来实现控件(如用于普通网页的边栏菜单)。
在某些情况下,可能需要对应用程序禁止任何外部导航。若要禁用所有外部导航,在初始化 Silverlight 插件时,应将 enableNavigation 属性设置为 none。
若要启用对其他网页的用户导航,可以使用 HyperlinkButton 控件并将 NavigateUri 属性设置为外部资源,将 TargetName 属性设置为打开新的浏览器窗口。
下面的代码示例演示如何使用 HyperlinkButton 导航到应用程序外的某个位置。





需要以编程方式从某一页启动导航请求时,必须首先获取宿主框架使用的 NavigationService 对象。NavigationService 类提供用于页导航的成员,如 GoBack、GoForward 和 Source。
下面是我自己做的一个小例子,没用SDK带的那个。那个例子对如何调用页面没有介绍。


我在这个例子中没有用到数据库,只是用了一个XML文件作为数据源。为了更方便的传递所有信息,我建了一个Product类,其中包含名称、数量、价钱、图片地址这些公共属性。在读取完XML数据后,生成List<product>,然后再把它赋值给ListBox控件的ItemsSource属性。
在ListBox控件中,我使用DisplayMemberPath="Name"来只显示Product Name。
然后在MainPage.xaml文件中,添加地址映射如下,注意用"& amp;"(中间无空格)来取代&




此时,我们就可以通过编程方式来导航了。在ListBox控件的SelectionChanged事件中,我们通过NavigationService来实现页面导航,代码如下

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox listbox = sender as ListBox;
Product product = (Product)listbox.SelectedItem;
NavigationService.Navigate(new Uri("/ProductDetail/" + product.Name+"/"+product.Price+"/"+product.Quantity+"/"+product.ImageUri, UriKind.RelativeOrAbsolute));
}

由于我们是把Product赋值给ListBox,所以通过Product product = (Product)listbox.SelectedItem,现在我们很容易就获得了所选产品的所有信息,而不仅仅是名字。然后把这些信息放到所想访问的地址中去,再通过NavigationService.Navigate来实现页面调用。
在ProductDetail页中,我们通过NavigationContext来获得传递的参数,代码如下

protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (this.NavigationContext.QueryString.ContainsKey("ProductName"))
{
productName.Text = NavigationContext.QueryString["ProductName"];
productQuantity.Text = "Quantity : "+ NavigationContext.QueryString["ProductQuantity"];
... ...
}
}

至此,我们就可以像在ASP.NET中那样,在任意页面中导航了。

2010年1月11日星期一

Silverlight 导航概述 1

本文摘自Silverlight3 SDK 导航概述

应用程序导航

在 Silverlight 应用程序中使用 Frame 和 Page 控件可以实现应用程序导航。页面(Page)控件表示内容的独立部分。框架(Frame)用作页面控件的容器,并使页导航非常简便。在任一时刻,框架只显示一个页面的内容。以编程方式或通过用户操作导航到新页时,框架中显示的页将会更改。
可以将 Silverlight 应用程序的根视觉效果设计为包含可导航内容和永久用户界面 (UI) 组件(例如页眉、页脚和导航边栏)的组合。使用"Silverlight 导航应用程序"模板创建新项目时,该模板会生成一个包含永久 UI 组件的 XAML 文件并为可导航内容生成一个框架。
下面的示例演示一个简单框架,它存在于名为 MainPage 的 UserControl 控件内。您可以在 ContentFrame 之前或之后向 LayoutRoot 添加其他 UI 组件。Source 设置为 /Views/Home.xaml 表示默认情况下,框架中显示的页是位于 /Views/Home.xaml 的页。在实际创建的应用程序中,Source被简单设置为/Home

通过使用"添加新项"对话框,然后选择"Silverlight 页",可以将新页添加到应用程序中。Visual Studio 中的"Silverlight 导航应用程序"模板会创建一个名为 Views 的文件夹,其中包含这些页。您可以向此文件夹添加页,也可以在应用程序中最适当的任何位置添加页。

创建用户友好的 URI

在框架中,可以为特定页面指定某种 URI 模式映射。使用 URI 映射可以创建说明用户操作的 URI,而不是文件的路径。例如,可以指定对 /Home 的任何请求实际上是对位于 /Views/Home.xaml 的文件的请求。不与任何已定义模式匹配的所有请求都作为常规 URI 请求来处理,不会映射到其他页。下表演示 URI 映射定义的示例以及如何解析这些示例请求。

URI 映射定义: Uri = "/Home" MappedUri = "/Views/Home.xaml"
匹配 URI 示例 : /Home 解析后的 URI : /Views/Home.xaml
URI 映射定义: Uri = "/{page}" MappedUri = "/Views/{page}Page.xaml"
匹配 URI 示例 : /About 解析后的 URI : /Views/AboutPage.xaml
URI 映射定义: Uri = "/Product/{category}" MappedUri = "/ContosoShop/Product.xaml?category={category}"
匹配 URI 示例 : /Product/bikes 解析后的 URI : /ContosoShop/Product.xaml?category=bikes
URI 映射定义: Uri = "/{reporttype}/{month}/{format}"
(在 XAML 中)MappedUri = "/Views/Reports/{reporttype}.xaml?time={month}&show={format}"
(在 Visual Basic 或 C# 中)MappedUri = "/Views/Reports/{reporttype}.xaml?time={month}&show={format}"
匹配 URI 示例 : /Sales/June/Short
解析后的 URI : /Views/Reports/Sales.xaml?time=June&show=Short

向框架添加 URI 映射的方法是定义 UriMapper 类(或派生自 UriMapperBase 类的自定义类)的一个实例以及任意数量的 UriMapping 实例。您指定的模式不必是与所请求 URI 完全匹配的 URI。该模式可以在 URI 中包含占位符段,URI 将匹配该段中的任何值。将占位符段的名称括在大括号({ 和 })中可以指定占位符段。在映射 URI 时,占位符段充当变量。任何没有括在大括号中的值表示文本值,要与模式匹配的 URI 必须存在该值。下面的示例演示包含占位符值的 URI 模式。















URI 请求将映射为与该请求匹配的第一个模式。因此,应按照从最具体到最一般的顺序添加 URI 映射实例。例如,下面的定义是按照从具体文本值到一般占位符值正确排序的。对 /SalesReport 的请求将映射为 /Views/Reports/Sales.xaml















但是,如果颠倒 URI 映射定义的顺序,对 /SalesReport 的请求将不会映射为 /Views/Reports/Sales.xaml。相反,第一个定义 /{page} 将匹配每一个段请求,包括 /SalesReport。该请求将映射为 /Views/SalesReportPage.xaml。

方便页导航

Frame 类提供用于页导航的方法和属性。将 Source 属性设置为要显示的页的 URI,或调用 Navigate 方法并将该页的 URI 作为参数来传递。也可以使用 GoBack 和 GoForward 方法在导航历史记录中向前或向后导航。
可以使用 HyperlinkButton 控件使用户能够在应用程序的各页中导航。宿主框架将导航到请求的页。下面的示例演示一个包含了导航到应用程序中另一页的 HyperlinkButton 的页。








2010年1月7日星期四

Sushi Menu

在blend3中看到一个颜色板的例子,觉得可以用来展示菜单。
于是就做了个简单的寿司菜单例子。
这个例子中用到的主要元素是listbox控件。通过ItemsPanel属性调用自定义模板,使内容旋转排版。
这个自定义模板是通过一个继承Panel的类来实现的。在每次渲染(重载ArrangeOverride函数)时,遍历容器内的所有子控件,使它们旋转一定的角度。

2010年1月5日星期二

安装silverlight新版本出现问题

前两天有个朋友想看这个博客,可发现需要安装新版本的silverlight,于是就下载了安装软件,却发现安装不了。总是跳出需要silverlight.msi文件的提示。其实这是由于他安装过以前的版本,在安新版本之前,需要这个文件卸载掉老版本。
可以从微软的网站下下载个installer.exe,然后安装运行,在里面选择删除以前的silverlight版本。这样就可以安装新版本了。

2010年1月4日星期一

Music Player Version 2

光是播放音乐,显得功能太简单。所以又加上了歌词功能。把歌词和每句的时间放在了XML文件中,这样就可以在歌曲加载后,马上加载歌词。

2009年12月31日星期四

Music Player

喜欢听歌,就做了个简单的播放器。视频播放应该是同样的原理。
其中用WebClient读取XML文件来获取歌手和歌曲的信息。歌曲资源通过网络地址来获取,并没有存在本地。
这样就可以通过修改XML文件来更新曲目了,而不用每次修改代码。

2009年12月29日星期二