代码改变世界

Silverlight3系列(五)数据绑定 Data Binding 2

2010-01-27 14:45  Virus-BeautyCode  阅读(1351)  评论(2编辑  收藏  举报

      接着上面一篇,我们来讨论绑定集合等。

  

  首先看一下可以进行绑定集合的控件属性,暂时我就不翻译了,因为翻译不好,还不如读英文呢。

 

Name

Description

ItemsSource

 Points to the collection that has all the objects that will be shown in the list.

DisplayMemberPath

 Identifies the property that will be used to creat the display text for each item.

ItemTemplate

 Providers a data template that will be used to create the visual appearance of each item.This property acts as a far more powerful replacement for DisplayMemberPath.

ItemsPanel

 Providers a template that will be used to create the layout container that holds all the items in the list.

  这里你可能会想,什么类型的集合可以绑定到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;
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;
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客户端前台代码

  

代码
<UserControl xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" 
    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;
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方法

  

 

public override string ToString()
        {
            
return string .Format ("用户代码:{0} | 用户姓名:{1}",CustomerCode,CustomerName );
        }

 

  属性就不用修改了,还是<ListBox x:Name="lstCustomers" ></ListBox>,效果如下图

  3)提供一个数据模板,这样你可以显示任何排列好的对象属性值,后面将会讲到这种做法。

 

  到这里你可能又需要两外一个功能了,就是点击一个list中的item,在下面显示一下详细信息。你可以响应listbox的SelectionChanged事件,在事件代码中写上

     

 

 private void lstCustomers_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            gridCustomerDetails.DataContext 
= lstCustomers.SelectedItem;
        }

 

  前台设置为

 

代码
 <ListBox x:Name="lstCustomers" SelectionChanged="lstCustomers_SelectionChanged"></ListBox>
            
<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>

  然后再后台写上

  

代码
 private void btnDelCustomer_Click(object sender, RoutedEventArgs e)
        {
            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的。

  

代码
IEnumerable<Customer> maths = from c in customers
                                          
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));
            }
        }
    }
}

 

 

 

  

代码
 #region IServiceCustomer Members

        
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服务, 对传输信息做加密       

 

  

      代码可以在http://silverlightwcf.codeplex.com/下载。