這是上一篇“Silverlight:雙向繫結綜合應用-自動更新集合彙總欄位”的續篇。需求情境如下:一個公司,有N個員工,逢年過節時要搞一些抽獎活動,最終要公告收獎名單。"員工"類如下:
namespace CollectionBinding{ /// <summary> /// 員工類 /// </summary> public class Employee : NotifyPropertyChangedObject { private string _name = ""; public string Name { set { _name = value; OnPropertyChanged("Name"); } get { return _name; } } private int _salary = 0; public int Salary { get { return _salary; } set { _salary = value; OnPropertyChanged("Salary"); } } }}“員工中獎記錄”類如下:
namespace CollectionBinding{ /// <summary> /// 員工中獎記錄 /// </summary> public class EmployeePrize : NotifyPropertyChangedObject { private string _employeeName = ""; /// <summary> /// 中獎員工的名字 /// </summary> public string EmployeeName { get { return _employeeName; } set { _employeeName = value; OnPropertyChanged("EmployeeName"); } } private string _prizeName = ""; /// <summary> /// 獎品名稱 /// </summary> public string PrizeName { get { return _prizeName; } set { _prizeName = value; OnPropertyChanged("PrizeName"); } } }}NotifyPropertyChangedObject是一個基類
using System.ComponentModel;namespace CollectionBinding{ public class NotifyPropertyChangedObject : INotifyPropertyChanged { public NotifyPropertyChangedObject() { } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }}錄入中獎員工時,要求“員工的名字”必須從公司的員工中選取,如果發現某位員工在公司的員工庫裡沒有登記,也可以在這個介面上的員工列表中臨時添加。介面原型如下:即:下面網格中的員工“姓名下拉框”資料來源,依賴於上面網格中的員工姓名記錄。(類似資料庫中的主從表關係)為了實現這種綁定,需要建立二個ViewModel類EmployeePrizeViewModel類,用來實現下面一個網格的綁定,代碼如下:
using System.ComponentModel;using System.Collections.ObjectModel;namespace CollectionBinding{ public class EmployeePrizeViewModel : NotifyPropertyChangedObject { private ObservableCollection<Employee> _employees = new ObservableCollection<Employee>(); public ObservableCollection<Employee> Employees { get { return _employees; } set { _employees = value; OnPropertyChanged("Employees"); } } private EmployeePrize _employeePrize = new EmployeePrize(); public EmployeePrize EmployeePrize { get { return _employeePrize; } set { _employeePrize = value; OnPropertyChanged("EmployeePrize"); } } }}上面的網格綁定,用CompanyViewModel來實現
using System.Collections.ObjectModel;using System.Collections.Specialized;using System.ComponentModel;using System.IO;using System.Linq;using System.Text;using System.Xml.Serialization;namespace CollectionBinding{ public class CompanyViewModel : NotifyPropertyChangedObject { private ObservableCollection<Employee> _employeeCollection = new ObservableCollection<Employee>(); /// <summary> /// 公司的"員工集合" /// </summary> public ObservableCollection<Employee> EmployeeCollection { get { return _employeeCollection; } } private ObservableCollection<EmployeePrizeViewModel> _employeePrizeViewModelCollection = new ObservableCollection<EmployeePrizeViewModel>(); /// <summary> /// 中獎名單 /// </summary> public ObservableCollection<EmployeePrizeViewModel> EmployeePrizeViewModelCollection { get { return _employeePrizeViewModelCollection; } } /// <summary> /// 建構函式 /// </summary> public CompanyViewModel() { _employeeCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(_employeeCollection_CollectionChanged); } /// <summary> /// 員工有“增減”時自動觸發 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void _employeeCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { //重新計算工資總和 computeSalaryTotal(); //每個員工的“工資”屬性變化時,自動觸發指定事件 foreach (var item in _employeeCollection) { item.PropertyChanged -= new PropertyChangedEventHandler(item_PropertyChanged); item.PropertyChanged += new PropertyChangedEventHandler(item_PropertyChanged); } } /// <summary> /// 員工屬性變化時自動調用本方法 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void item_PropertyChanged(object sender, PropertyChangedEventArgs e) { //如果是"工資"屬性變化,則自動重新計算工資匯總 if (e.PropertyName == "Salary") { computeSalaryTotal(); } } private void computeSalaryTotal() { _salaryTotal = _employeeCollection.Sum(c => c.Salary); OnPropertyChanged("SalaryTotal");//工資總合重新計算後,向外廣播事件,以便UI能自動更新 } private int _salaryTotal = 0; /// <summary> /// 工資匯總 /// </summary> public int SalaryTotal { get { return _salaryTotal; } } public override string ToString() { string result = ""; XmlSerializer xmlSerializer = new XmlSerializer(typeof(CompanyViewModel)); using (MemoryStream ms = new MemoryStream()) { try { xmlSerializer.Serialize(ms, this); result = Encoding.UTF8.GetString(ms.ToArray(), 0, (int)ms.Length); } catch { } } return result; } }}類圖:
最終介面的Xaml代碼:
<UserControl x:Class="CollectionBinding.MainPage" 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" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"> <StackPanel x:Name="LayoutRoot" Background="White"> <sdk:DataGrid AutoGenerateColumns="False" HorizontalAlignment="Center" Margin="0,10,0,0" Name="dataGrid1" VerticalAlignment="Center" ItemsSource="{Binding EmployeeCollection,Mode=TwoWay}"> <sdk:DataGrid.Columns> <sdk:DataGridTemplateColumn Header="姓名" Width="100"> <sdk:DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding Name,Mode=TwoWay}" VerticalAlignment="Center" Margin="1"></TextBox> </DataTemplate> </sdk:DataGridTemplateColumn.CellTemplate> </sdk:DataGridTemplateColumn> <sdk:DataGridTemplateColumn Header="工資" Width="100"> <sdk:DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding Salary,Mode=TwoWay}" VerticalAlignment="Center" Margin="1"></TextBox> </DataTemplate> </sdk:DataGridTemplateColumn.CellTemplate> </sdk:DataGridTemplateColumn> <sdk:DataGridTemplateColumn Header="操作"> <sdk:DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Click="RemoveEmployee" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="10,1">-</Button> </DataTemplate> </sdk:DataGridTemplateColumn.CellTemplate> </sdk:DataGridTemplateColumn> </sdk:DataGrid.Columns> </sdk:DataGrid> <StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Margin="5"> <TextBlock VerticalAlignment="Center">工資總合:</TextBlock> <TextBlock Text="{Binding SalaryTotal, Mode=TwoWay}" Margin="5,0,5,0" Width="60"></TextBlock> </StackPanel> <Button Click="AddEmployee" Padding="10,1" Margin="5" HorizontalAlignment="Center">+</Button> <Border BorderBrush="Black" BorderThickness="0,1,0,0" Width="300"></Border> <sdk:DataGrid AutoGenerateColumns="False" HorizontalAlignment="Center" Margin="0,10,0,0" Name="dataGrid2" VerticalAlignment="Center" ItemsSource="{Binding EmployeePrizeViewModelCollection,Mode=TwoWay}"> <sdk:DataGrid.Columns> <sdk:DataGridTemplateColumn Header="姓名" Width="100"> <sdk:DataGridTemplateColumn.CellTemplate> <DataTemplate> <ComboBox ItemsSource="{Binding Employees,Mode=TwoWay}" SelectedValuePath="Name" SelectedValue="{Binding EmployeePrize.EmployeeName,Mode=TwoWay}"> <ComboBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}"></TextBlock> </StackPanel> </DataTemplate> </ComboBox.ItemTemplate> </ComboBox> </DataTemplate> </sdk:DataGridTemplateColumn.CellTemplate> </sdk:DataGridTemplateColumn> <sdk:DataGridTemplateColumn Header="獎品" Width="100"> <sdk:DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBox Text="{Binding EmployeePrize.PrizeName,Mode=TwoWay}" VerticalAlignment="Center" Margin="1"></TextBox> </DataTemplate> </sdk:DataGridTemplateColumn.CellTemplate> </sdk:DataGridTemplateColumn> <sdk:DataGridTemplateColumn Header="操作"> <sdk:DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Click="RemoveEmployeePrize" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="10,1">-</Button> </DataTemplate> </sdk:DataGridTemplateColumn.CellTemplate> </sdk:DataGridTemplateColumn> </sdk:DataGrid.Columns> </sdk:DataGrid> <Button Click="AddEmployeePrize" Padding="10,1" Margin="5" HorizontalAlignment="Center">+</Button> <Button HorizontalAlignment="Center" Padding="10,2" Click="ShowCompanyViewModel">查看CompanyViewModel內容</Button> <TextBox Name="textBox1" Margin="5" Height="200" TextWrapping="Wrap" ScrollViewer.VerticalScrollBarVisibility="Visible"/> </StackPanel></UserControl>後面Xaml.cs 部分:
using System.Windows;using System.Windows.Controls;namespace CollectionBinding{ public partial class MainPage : UserControl { CompanyViewModel c = new CompanyViewModel(); public MainPage() { InitializeComponent(); this.Loaded += new RoutedEventHandler(MainPage_Loaded); } void MainPage_Loaded(object sender, RoutedEventArgs e) { //偽造一些資料,測試綁定 Employee e1 = new Employee() { Name = "張三", Salary = 3000 }; Employee e2 = new Employee() { Name = "李四", Salary = 4000 }; Employee e3 = new Employee() { Name = "楊過", Salary = 9999 }; c.EmployeeCollection.Add(e1); c.EmployeeCollection.Add(e2); c.EmployeeCollection.Add(e3); EmployeePrizeViewModel p1 = new EmployeePrizeViewModel() { Employees = c.EmployeeCollection, EmployeePrize = new EmployeePrize() { EmployeeName = "楊過", PrizeName = "玄鐵劍" } }; EmployeePrizeViewModel p2 = new EmployeePrizeViewModel() { Employees = c.EmployeeCollection, EmployeePrize = new EmployeePrize() { EmployeeName = "李四", PrizeName = "ThinkPad X220" } }; c.EmployeePrizeViewModelCollection.Add(p1); c.EmployeePrizeViewModelCollection.Add(p2); this.DataContext = c; } /// <summary> /// 刪除員工 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void RemoveEmployee(object sender, RoutedEventArgs e) { var emp = (sender as Button).DataContext as Employee; if (emp != null) { c.EmployeeCollection.Remove(emp); } } /// <summary> /// 添加員工 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void AddEmployee(object sender, RoutedEventArgs e) { c.EmployeeCollection.Add(new Employee() { Name = "新人", Salary = 1000 }); } /// <summary> /// 增加中獎名單 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void AddEmployeePrize(object sender, RoutedEventArgs e) { var empPrizeViewModel = new EmployeePrizeViewModel() { Employees = c.EmployeeCollection }; var empPrize = new EmployeePrize(); if (c.EmployeeCollection.Count > 0) { empPrize.EmployeeName = c.EmployeeCollection[c.EmployeeCollection.Count - 1].Name; } empPrizeViewModel.EmployeePrize = empPrize; c.EmployeePrizeViewModelCollection.Add(empPrizeViewModel); } /// <summary> /// 刪除中獎名單 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void RemoveEmployeePrize(object sender, RoutedEventArgs e) { var empPrizeViewModel = (sender as Button).DataContext as EmployeePrizeViewModel; if (empPrizeViewModel != null) { c.EmployeePrizeViewModelCollection.Remove(empPrizeViewModel); } } private void ShowCompanyViewModel(object sender, RoutedEventArgs e) { this.textBox1.Text = c.ToString(); } }}線上示範地址:
http://img.24city.com/jimmy/sl4/collectionbinding/樣本源碼下載:http://files.cnblogs.com/yjmyzz/CollectionBinding.7z