今天我们讨论的是Silverlight3中的数据绑定,内容来自 《Pro Silverlight3 in C#》的读后感,中文名称可以译为《Silverlight3高级编程 C#版》。我找到的是一本PDF的,在网上可以搜索到下载地址。
数据绑定提供了一种,从对象中获取信息,然后显示在你的应用程序的界面上,同时不需要写冗长的代码就可以完成所有的工作的方式。通常情况下,富客户端提供两种绑定方式,不仅可以从兑现获取数据,显示到界面上,也可以将界面的数据传回给对象。
Silverlight是不允许客户端直接使用ADO.NET直接连接数据库,进行数据库操作的。只能通过代理的方式操作数据库,通过第三方,例如:webservice、wcf、ado.net data service、ric service等服务性的方式。
1、绑定到数据对象
例如现在又一个Customer的实体对象
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
public class Customer
{
private int _intCustomerId;
private string _strCustomerName;
private string _strCustomerCode;
[DataMember]
public virtual int CustomerId
{
get { return this ._intCustomerId; }
set { this ._intCustomerId = value; }
}
[DataMember]
public virtual string CustomerName
{
get { return this ._strCustomerName; }
set { this ._strCustomerName = value; }
}
[DataMember]
public virtual string CustomerCode
{
get { return _strCustomerCode; }
set { this ._strCustomerCode = value; }
}
}
想要达到下图的一种效果
![](https://i-blog.csdnimg.cn/blog_migrate/bc9d36f195e48a1bc4b67a1d5083aa85.jpeg)
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
< Grid.ColumnDefinitions >
< ColumnDefinition />
< ColumnDefinition />
</ Grid.ColumnDefinitions >
< Grid.RowDefinitions >
< RowDefinition Height ="20" />
< RowDefinition Height ="20" />
< RowDefinition Height ="20" />
< RowDefinition Height ="20" />
< RowDefinition Height ="20" />
< RowDefinition Height ="20" />
</ Grid.RowDefinitions >
< TextBlock x:Name ="LblCustomerId" Grid.Column ="0" Grid.Row ="0" Text ="Customer Id" />
< TextBlock x:Name ="TxtCustomerId" Grid.Column ="1" Grid.Row ="0" Text ="{Binding CustomerId}" />
< TextBlock x:Name ="LblCustomerCode" Grid.Column ="0" Grid.Row ="1" Text ="Customer Code" />
< TextBlock x:Name ="TxtCustomerCode" Grid.Column ="1" Grid.Row ="1" Text ="{Binding CustomerCode}" />
< TextBlock x:Name ="LblCustomerName" Grid.Column ="0" Grid.Row ="2" Text ="用户名称" />
< TextBlock x:Name ="TxtCustomerName" Grid.Column ="1" Grid.Row ="2" Text ="{Binding CustomerName}" />
</ Grid >
后台代码
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
{
Customer customer = new Customer() { CustomerId = 1 , CustomerCode = " ss " , CustomerName = " dddd " };
LayoutRoot.DataContext = customer;
}
2、将数据对象存储为资源
首先要在类代码中存在一个资源对象,
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
{
public class Users
{
public string Firstname { get ; set ; }
public string Lastname { get ; set ; }
}
public partial class DataBindingDemo : UserControl
{
public DataBindingDemo()
{
InitializeComponent();
}
}
}
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
xmlns = " http://schemas.microsoft.com/winfx/2006/xaml/presentation "
xmlns:x = " http://schemas.microsoft.com/winfx/2006/xaml "
xmlns:local = " clr-namespace:Silverlight "
Width = " 400 " Height = " 300 " >
< UserControl.Resources >
< local:Users x:Key = " SingleUser " Firstname = " virus " Lastname = " ssss " ></ local:Users >
</ UserControl.Resources >
< Grid x:Name = " LayoutRoot " Background = " White " >
< TextBox Text = " {Binding Path=Firstname,Source={StaticResource SingleUser}} " ></ TextBox >
</ Grid >
</ UserControl >
上面的红色部分的xmlns:local="clr-namespace:Silverlight"是定义资源的命名空间,
<UserControl.Resources>
<local:Users x:Key="SingleUser" Firstname="virus" Lastname="ssss"></local:Users>
</UserControl.Resources>
是定义一个资源
<TextBox Text="{Binding Path=Firstname,Source={StaticResource SingleUser}}"></TextBox>
是绑定到控件,源是SingleUser,绑定的具体属性是Firstname。如果是绑定一个属性的话,每次都需要设置Source的值,如果是绑定到一个Grid上面的话,可以使用<Grid Name="gridUsers" DataContext="{StaticResource SingleUser}">来绑定。
3、可编辑的双向绑定
到这里你可能想要知道,如果我在界面上修改一个值,会发生什么呢?例如你修改了界面上面的文本框的值,文本框的值绑定了一个对象的属性,在内存中的对象属性会改变吗?
实际上,内存中的对象属性没有任何变化,因为Silverlight默认使用单向绑定。
System.Windows.Data.BindingMode枚举量中定义了全部的绑定类型,如下表:
Name | Description |
OneWay 单向绑定 | 当对象属性改变的时候,绑定对象就会改变 |
TwoWay 双向绑定 | 当源对象属性改变的时候,绑定对象会改变;反过来,绑定对象的改变也会影响源对象属性的改变。 |
OneTime 一次性绑定 | 绑定对象在第一次初始化的时候显示对象的属性,后面不会随着对象属性的改变而改变,这种适用于你确定对象的属性几乎不会改变的情况下。 |
<TextBox Text="{Binding Firstname, Mode=TwoWay}"></TextBox>
如果你使用了双向绑定,如果你修改了textbox的值,当你的鼠标焦点一离开textbox之后(焦点在两外一个控件,或者点击一个按钮),内存中的对象属性Firstname就会发生改变,执行属性的set。
使用了双向绑定之后,焦点一离开控件之后就会触发内存对象的改变,但是有的时候我们想精确控制,而不是等焦点移除的时候,例如:输入框在用户输入的同时就进行,而不是等用户焦点移出输入框,你可以在代码中调用 BindingExpression.UpdateSource();
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
{
BindingExpression expression = txtFirstname.GetBindingExpression(TextBox.TextProperty);
expression.UpdateSource();
}
使用上面的代码,你就可以在用户进入文本框和输入的时候就强迫文本框更新源对象的属性值。如果你全部的控件都是用这样的更新方式,你就可以禁用Silverlight的自动更新功能,设置UpdateSourceTrigger属性的值为Explicit。
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
Text ="{Binding Path=Firstname,Source={StaticResource SingleUser}, Mode=TwoWay, UpdateSourceTrigger=Explicit}"
TextChanged ="txtFirstname_TextChanged" ></ TextBox >
在Silverlight中UpdateSourceTrigger有两个属性值可以设置:Default和Explicit。
4、数据验证 Validation
数据验证将在下一篇中重点讲解。先提供一个实例代码下载:DataValidation
验证的话,就需要Silverlight客户端和wcf服务端共享类库,共享实体类,因为服务端的实体类虽然被序列化到客户端,但是只能序列化状态信息,就是成员,方法之类的不会序列化的,而且就算序列化过来,也没有什么用,运行环境context都不一样了,没有什么意思。所以可能会用到客户端和服务端共享类库,可以参考下面的文章。
Silverlight客户端和WCF服务器端共享类库
5、绑定到一个数据服务
更复杂的数据绑定中,数据可能是从外部服务获取的。这里的外部服务使用wcf来提供,下面的代码假定你已经了解wcf,如果不了解的可以看老徐的博客或者google一些资料来看。数据库操作部分使用NHibernate 2.1.2完成。
首先定义数据交互契约
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ComponentModel;
using System.Runtime.Serialization;
namespace Domain.Server
{
[DataContract]
public class Customer : INotifyPropertyChanged
{
private int _intCustomerId;
private string _strCustomerName;
private string _strCustomerCode;
[DataMember]
public virtual int CustomerId
{
get { return this._intCustomerId; }
set
{
this._intCustomerId = value;
OnPropertyChanged("CustomerId");
}
}
[DataMember]
public virtual string CustomerName
{
get { return this._strCustomerName; }
set
{
this._strCustomerName = value; OnPropertyChanged("CustomerName");
}
}
[DataMember]
public virtual string CustomerCode
{
get { return _strCustomerCode; }
set
{
this._strCustomerCode = value;
OnPropertyChanged("CustomerCode");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
wcf服务代码
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using Domain.Server;
using Common.Core;
using Common.Data;
namespace WcfService
{
public class ServiceCustomer : IServiceCustomer
{
private CustomerDAO _customerDao;
Common.Core.Utility.NHibernateUtility _NHUtility;
MyValidator _myValidator;
public ServiceCustomer()
{
_NHUtility = new Common.Core.Utility.NHibernateUtility();
_customerDao = new CustomerDAO(_NHUtility.GetSession());
//string name = OperationContext.Current.ServiceSecurityContext.PrimaryIdentity.Name;
}
// Add more operations here and mark them with [OperationContract]
public Domain.Server.Customer GetCustomer(int customerId)
{
Domain.Server.Customer objCustomer = new Domain.Server.Customer();
return _customerDao.GetCustomerById(customerId);
}
}
}
Silverlight的前台代码
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
< Grid.ColumnDefinitions >
< ColumnDefinition />
< ColumnDefinition />
</ Grid.ColumnDefinitions >
< Grid.RowDefinitions >
< RowDefinition Height ="20" />
< RowDefinition Height ="20" />
< RowDefinition Height ="20" />
< RowDefinition Height ="20" />
< RowDefinition Height ="20" />
< RowDefinition Height ="20" />
</ Grid.RowDefinitions >
< TextBlock x:Name ="LblCustomerId" Grid.Column ="0" Grid.Row ="0" Text ="Customer Id" />
< TextBlock x:Name ="TxtCustomerId" Grid.Column ="1" Grid.Row ="0" Text ="{Binding CustomerId}" />
< TextBlock x:Name ="LblCustomerCode" Grid.Column ="0" Grid.Row ="1" Text ="Customer Code" />
< TextBlock x:Name ="TxtCustomerCode" Grid.Column ="1" Grid.Row ="1" Text ="{Binding CustomerCode}" />
< TextBlock x:Name ="LblCustomerName" Grid.Column ="0" Grid.Row ="2" Text ="用户名称" />
< TextBlock x:Name ="TxtCustomerName" Grid.Column ="1" Grid.Row ="2" Text ="{Binding CustomerName}" />
</ Grid >
Silverlight的后台代码
![](https://i-blog.csdnimg.cn/blog_migrate/cdec0645add3fc3c328197dda5c76203.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/81178cc93a2a3bb5048d90d76e7ec935.gif)
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 Silverlight.ServiceCustomer;
namespace Silverlight
{
public partial class sldbdemo : UserControl
{
ServiceCustomerClient client;
SysUser _sysUser;
public sldbdemo()
{
InitializeComponent();
client = new ServiceCustomerClient();
GetCustomerById(1);
}
protected void GetCustomerById(int customerId)
{
try
{
client.GetCustomerCompleted += new EventHandler < GetCustomerCompletedEventArgs > (client_GetCustomerCompleted);
client.GetCustomerAsync( customerId);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.InnerException.Message);
}
}
void client_GetCustomerCompleted(object sender, GetCustomerCompletedEventArgs e)
{
LayoutRoot.DataContext = e.Result;
}
}
}
代码无误,就应该看到下面的内容,前提是数据库有Id=1的用户信息。数据操作部分也可以自己写DbConnection来做,效果是一样的。
![](https://i-blog.csdnimg.cn/blog_migrate/bc9d36f195e48a1bc4b67a1d5083aa85.jpeg)
6、绑定一个数据集合
下文继续。