接着上面一篇,我们来讨论绑定集合等。
首先看一下可以进行绑定集合的控件属性,暂时我就不翻译了,因为翻译不好,还不如读英文呢。
Name |
Description |
ItemsSource |
|
DisplayMemberPath |
|
ItemTemplate |
|
ItemsPanel |
|
这里你可能会想,什么类型的集合可以绑定到ItemsSource属性呢?告诉你,只需要实现IEnumerable就可以,但是,实现这个借口的集合是只读的。如果你想编辑这个集合,例如允许插入和删除,你需要更多的工作,后面我们会介绍。
显示并且编辑集合项
首先定义个数据库交互契约
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ComponentModel;
using System.Runtime.Serialization;
namespace Domain.Entity
{
[DataContract]
public class Customer : INotifyPropertyChanged
{
private int _intCustomerId;
private string _strCustomerName;
private string _strCustomerCode;
private CustomerType _CustomerType;
private int _intCustomerTypeId;
[DataMember ]
public virtual int CustomerTypeId
{
get { return _intCustomerTypeId; }
set { _intCustomerTypeId = value; }
}
[DataMember ]
public virtual CustomerType CustomerType
{
get { return this._CustomerType; }
set
{
this._CustomerType = value;
OnPropertyChanged("CustomerType");
}
}
[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定义接口
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using Domain.Entity;
namespace WcfService
{
[ServiceContract]
public interface IServiceCustomer
{
[OperationContract]
Domain.Entity.Customer GetCustomer(int customerId);
[OperationContract]
IList<Domain.Entity.Customer> GetAll();
[OperationContract]
void Add(Domain.Entity.Customer customer);
[OperationContract]
string SayHello(SysUser sysUser);
}
}
实现这个接口
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.Entity;
using Common.Core;
using Common.Data;
namespace WcfService
{
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
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());
}
// Add more operations here and mark them with [OperationContract]
#region IServiceCustomer Members
public Domain.Entity.Customer GetCustomer( int customerId)
{
Domain.Entity.Customer objCustomer = new Domain.Entity.Customer();
return _customerDao.GetCustomerById(customerId);
}
#endregion
#region IServiceCustomer Members
public IList<Domain.Entity.Customer> GetAll()
{
IList<Domain.Entity.Customer> cs = _customerDao.GetAll();
return cs;
}
#endregion
#region IServiceCustomer Members
public void Add(Domain.Entity.Customer customer)
{
_customerDao.CreateCustomer(customer);
}
#endregion
#region IServiceCustomer Members
public string SayHello(SysUser sysUser)
{
_myValidator = (MyValidator)OperationContext.Current.Host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator;
return string.Format("hello,{0},your password is {1}\n{2}{3}", sysUser.UserName, sysUser.Password,
// _myValidator.ToString(),_myValidator.ToString() );
_myValidator.UserName ,_myValidator.Password );
}
#endregion
}
}
Silverlight客户端前台代码
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="Silverlight.sldbdemo"
Width="400">
<ScrollViewer>
<StackPanel>
<Button x:Name="btnGetCustomer" Content="获取一个用户信息" Click="btnGetCustomer_Click"></Button>
<Grid x:Name="LayoutRoot" Background="White">
<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>
<Button x:Name="btnGetAllCustomer" Content="获取全部用户信息" Click="btnGetAllCustomer_Click"></Button>
<Grid x:Name="customers" Background="Gray" Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="3">
<data:DataGrid x:Name="dataGrid" CanUserResizeColumns="true" CanUserSortColumns="True"
AutoGenerateColumns="False" ItemsSource="{Binding}">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="Id" Binding="{Binding CustomerId}"></data:DataGridTextColumn>
<data:DataGridTextColumn Header="Code" Binding="{Binding CustomerCode}"></data:DataGridTextColumn>
<data:DataGridTextColumn Header="Name" Binding="{Binding CustomerName}"></data:DataGridTextColumn>
</data:DataGrid.Columns>
</data:DataGrid>
</Grid>
<StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="4">
<data:DataPager x:Name="tempPager" DisplayMode="FirstLastPreviousNextNumeric" HorizontalAlignment="Left" VerticalAlignment="Top"
Source="{Binding Path=ItemsSource,ElementName=dataGrid}"
PageSize="5"
></data:DataPager>
</StackPanel>
<Grid x:Name="AddCustomer" Background="White" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="5" Height="97">
<Grid.ColumnDefinitions >
<ColumnDefinition Width="0.5*"></ColumnDefinition>
<ColumnDefinition Width="0.5*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions >
<RowDefinition Height="0.247*" ></RowDefinition>
<RowDefinition Height="0.247*" ></RowDefinition>
<RowDefinition Height="0.247*" ></RowDefinition>
<RowDefinition Height="0.258*" ></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="Customer Id" Grid.Column="0" Grid.Row="0"></TextBlock>
<TextBox x:Name="customerId" Grid.Column="1" Grid.Row="0"></TextBox>
<TextBlock Text="Custoemr Code" Grid.Column="0" Grid.Row="1"></TextBlock>
<TextBox x:Name="customerCode" Grid.Column="1" Grid.Row="1"></TextBox>
<TextBlock Text="Customer Name" Grid.Column="0" Grid.Row="2"></TextBlock>
<TextBox x:Name="customerName" Grid.Column="1" Grid.Row="2"></TextBox>
<Button x:Name="btnOk" Grid.Column="0" Grid.Row="3" Height="25" Content="添加用户Add Customer" Click="btnOk_Click"></Button>
</Grid>
<Button x:Name="btnLoadData" Click="btnLoadData_Click" Content="加载数据"></Button>
<ListBox x:Name="lstCustomers"></ListBox>
</StackPanel>
</ScrollViewer>
</UserControl>
Silverlight客户端后台代码
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;
using Domain.Entity;
namespace Silverlight
{
public partial class sldbdemo : UserControl
{
ServiceCustomerClient client;
SysUser _sysUser;
private int _customerId = 1;
public sldbdemo()
{
InitializeComponent();
client = new ServiceCustomerClient();
client.ClientCredentials.UserName.UserName = "adminstrator";
client.ClientCredentials.UserName.Password = "123.com";
_sysUser = new SysUser() { UserName = "swb", Password = "swb" };
client.SayHelloAsync(_sysUser);
client.SayHelloCompleted += new EventHandler<SayHelloCompletedEventArgs>(client_SayHelloCompleted);
}
void client_SayHelloCompleted(object sender, SayHelloCompletedEventArgs e)
{
try
{
MessageBox.Show(e.Result);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.InnerException.Message);
}
}
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)
{
// Customer customer = new Customer() { CustomerId = 1, CustomerCode = "ss", CustomerName = "dddd" };
//LayoutRoot.DataContext = customer;
LayoutRoot.DataContext = e.Result;
}
protected void LoadCustomers()
{
try
{
client.GetAllCompleted += new EventHandler<GetAllCompletedEventArgs>(client_GetAllCompleted);
client.GetAllAsync();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.InnerException.Message);
}
}
void client_GetAllCompleted(object sender, GetAllCompletedEventArgs e)
{
System.Windows.Data.PagedCollectionView page = new System.Windows.Data.PagedCollectionView(e.Result);
tempPager.Source = page;
dataGrid.ItemsSource = page;
}
private void btnOk_Click(object sender, RoutedEventArgs e)
{
try
{
client.AddCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(client_AddCompleted);
Domain.Entity.Customer customer = new Domain.Entity.Customer()
{
CustomerId = int.Parse(customerId.Text),
CustomerCode = customerCode.Text,
CustomerName = customerName.Text
};
client.AddAsync( customer);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + ex.InnerException.Message);
}
}
void client_AddCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
LoadCustomers();
}
private void btnLoadData_Click(object sender, RoutedEventArgs e)
{
client.GetAllAsync();
client.GetAllCompleted +=new EventHandler<GetAllCompletedEventArgs>(client_GetAllCompleted1);
}
void client_GetAllCompleted1(object sender, GetAllCompletedEventArgs e)
{
lstCustomers.ItemsSource = e.Result;
}
private void btnGetCustomer_Click(object sender, RoutedEventArgs e)
{
GetCustomerById(_customerId);
}
private void btnGetAllCustomer_Click(object sender, RoutedEventArgs e)
{
LoadCustomers();
}
}
}
效果图
你会看到后面的listbox中,数据显示的全部都是Domain.Entity.Customer,没有显示成我们想要的某一栏的值,这就是因为在代码中我们使用了lstCustomers.ItemsSource = e.Result;第一种绑定集合的属性,这时候就需要第二种绑定集合的属性 DisplayMemberPath="CustomerName"登场了。
其实实现上面的效果,你可以有三条途径:
1)设置控件的DisplayMemberPath属性为一个对象的属性名称,例如:DisplayMemberPath="CustomerName",效果如下图
2)重写对象的ToString()方法,提供一些有用的信息,设置可以显示几个属性,因为默认绑定使用的就是对象的tostring方法
{
return string .Format ("用户代码:{0} | 用户姓名:{1}",CustomerCode,CustomerName );
}
属性就不用修改了,还是<ListBox x:Name="lstCustomers" ></ListBox>,效果如下图
3)提供一个数据模板,这样你可以显示任何排列好的对象属性值,后面将会讲到这种做法。
到这里你可能又需要两外一个功能了,就是点击一个list中的item,在下面显示一下详细信息。你可以响应listbox的SelectionChanged事件,在事件代码中写上
{
gridCustomerDetails.DataContext = lstCustomers.SelectedItem;
}
前台设置为
<Grid x:Name="gridCustomerDetails" Background="White">
<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="LblCustomerIdd" Grid.Column="0" Grid.Row="0" Text="Customer Id"/>
<TextBlock x:Name="TxtCustomerIdd" Grid.Column="1" Grid.Row="0" Text="{Binding CustomerId}"/>
<TextBlock x:Name="LblCustomerCoded" Grid.Column="0" Grid.Row="1" Text="Customer Code"/>
<TextBlock x:Name="TxtCustomerCoded" Grid.Column="1" Grid.Row="1" Text="{Binding CustomerCode}"/>
<TextBlock x:Name="LblCustomerNamed" Grid.Column="0" Grid.Row="2" Text="用户名称"/>
<TextBlock x:Name="TxtCustomerNamed" Grid.Column="1" Grid.Row="2" Text="{Binding CustomerName}"/>
</Grid>
效果如下图
插入和删除集合中的项
你通过服务接口获取的数据集合可能是各种各样的,array、list等,但是在客户端他们的存储类型都是 System.Collections.ObjectModel.ObservableCollection,当你返回一个集合的时候,自动翻译类型。
这种设计是因为客户端不知道服务器会返回什么类型的集合,Silverlight假设使用 System.Collections.ObjectModel.ObservableCollection类型是安全的,因为 System.Collections.ObjectModel.ObservableCollection相对array、dictionary来说都有更多的功能。
在sl前台加上一个button
<Button x:Name="btnDelCustomer" Content="删除一个用户" Click="btnDelCustomer_Click"></Button>
然后再后台写上
{
System.Collections.ObjectModel.ObservableCollection<Customer> customers = (System.Collections.ObjectModel.ObservableCollection<Customer>)lstCustomers.ItemsSource ;
customers .Remove ((Customer )lstCustomers.SelectedItem );
}
在页面上就会看到效果,这只是从集合中删除,并没有从后端数据库删除,你加载一下的话,数据还是在的。如果要实现真正的数据操作,还是要利用wcf的服务来实现数据库的操作。
LINQ是.NET 3.5中的一个新型的数据查询方式,就是对对象集合的查询,更加面向对象的查询。它的查询结果是实现了IEnumerable<T>接口的,所以使用LINQ查询的结果也是可以绑定到ItemsSource的。
where c.CustomerName == "dd"
select c;
lstCustomers.ItemsSource = maths;
不像list或者ObserverableCollection,IEnumerable<T>接口没有提供添加或者删除方法。如果你需要的话,可以使用接口的toarray和tolist方法转化为有操作方法的集合,如果更加需要的话,还可以进一步搞成ObserverableCollection集合。
List<Customer > list = maths.ToList<Customer>();
接下来我们要实现的这么一种效果,就先下列出来所有的用户类型,然后选中类型之后,再显示当前类型的全部用户姓名,选中用户姓名之后,再显示用户详细信息。
我们要添加一个用户类型的定义,在wcf中要添加一个获取全部类型的接口。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ComponentModel;
using System.Runtime.Serialization;
using Iesi.Collections.Generic;
namespace Domain.Entity
{
[DataContract]
public class CustomerType : INotifyPropertyChanged
{
private string _strCustomerTypeName;
private int _intCustomerTypeId;
private ISet<Customer> _customers;
[DataMember ]
public virtual int CustomerTypeId
{
get { return this._intCustomerTypeId; }
set
{
this._intCustomerTypeId = value;
OnPropertyChanged("CustomerTypeId");
}
}
[DataMember]
public virtual string CustomerTypeName
{
get { return this._strCustomerTypeName; }
set
{
this._strCustomerTypeName = value; OnPropertyChanged("CustomerTypeName");
}
}
[DataMember]
public virtual ISet <Customer> Customers
{
get { return this._customers; }
set
{
this._customers = value;
OnPropertyChanged("Customers");
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
public IList<Customer> GetCustomerByTypeId(int typeId)
{
return _customerDao.GetCustomerByTypeId(typeId);
}
public IList<CustomerType> GetAllCustomerType()
{
return _customerTypeDao.GetAll();
}
#endregion
插入一个有用的连接,Silverlight 的 .NET Framework 类库,里面是Silverlight客户端可以使用的.NET类库。
稳扎稳打Silverlight(22) - 2.0通信之调用WCF服务, 对传输信息做加密