Silverlight:双向绑定综合应用-多集合的依赖绑定
时间:2022-04-23
本文章向大家介绍Silverlight:双向绑定综合应用-多集合的依赖绑定,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
这是上一篇“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
- 2014---多校训练2(ZCC Loves Codefires)
- 完整的golang 多协程+信道 任务处理示例
- 2014---多校训练一(A Couple doubi)
- hdu----(2586)How far away ?(DFS/LCA/RMQ)
- Golang控制goroutine的启动与关闭
- spring-boot-starter-swagger迎新伙伴支持,加速更新进度(1.3.0.RELEASE)
- poj----(1470)Closest Common Ancestors(LCA)
- 测试一下golang协程资源占有率
- poj----1330Nearest Common Ancestors(简单LCA)
- fasthttp中的协程池实现
- Oracle 12c R2版本 Application Containers 特性(二)
- go sync.Mutex 设计思想与演化过程 --转
- hadoop开发必读:认识Context类的作用
- Logback+ELK+SpringMVC搭建日志收集服务器
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ceph 分布式存储-块存储(RBD)搭建
- ceph 分布式存储-文件存储(CephFS)搭建
- 模拟 GROUP_CONCAT() 函数
- three.js 数学方法之Box3
- Redis Cluster服务平台化之路
- ceph分布式存储-对象存储(RGW)搭建
- 【PostgreSQL 架构】PostgreSQL 11和即时编译查询
- PG数量的预估
- ceph分布式存储-用户管理
- ceph分布式存储-检查集群健康状态
- ceph分布式存储-常见MON故障处理
- ceph分布式存储-常见OSD故障处理.md
- ceph分布式存储-常见 PG 故障处理
- ceph分布式存储-全局Ceph节点宕机处理
- ceph分布式存储-单个Ceph节点宕机处理