场景:有一家公司(类名:Company),它有N多员工(类名:Employee)。要在界面上用网格显示所有员工的姓名、工资,并且当操作用户在网格里对员工进行增减或修改其工资时,能自动汇总出员工工资的总和并显示出来。
员工类 Employee代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/// <summary>
/// 员工类
/// </summary>
public
class
Employee:INotifyPropertyChanged
{
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" ); }
}
public
event
PropertyChangedEventHandler PropertyChanged;
protected
void
OnPropertyChanged( string
propertyName)
{
if
(PropertyChanged != null ) {
PropertyChanged( this , new
PropertyChangedEventArgs(propertyName));
}
}
}
|
公司类 Company代码原型如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public
class
Company {
private
ObservableCollection<Employee> _employeeCollection = new
ObservableCollection<Employee>();
/// <summary>
/// 公司的"员工集合"
/// </summary>
public
ObservableCollection<Employee> EmployeeCollection
{
get
{ return
_employeeCollection; }
}
private
void
computeSalaryTotal()
{
_salaryTotal = _employeeCollection.Sum(c => c.Salary);
}
private
int
_salaryTotal = 0;
/// <summary>
/// 工资汇总
/// </summary>
public
int
SalaryTotal
{
get
{
computeSalaryTotal();
return
_salaryTotal;
}
}
}
|
常规解决办法:
可以在Grid每行“工资”字段对应的TextBox上,注册TextChanged或LostFocus事件,在输入值变化或失去焦点时,去更新总和。
这是很容易想到的办法,但是并不优雅,原因:
1、每行的TextBox上都要去绑定事件,并在xaml.cs上写代码处理类似 TextBoxTotal.text = company.SalaryTotal 的逻辑。这样界面逻辑代码与UI绑得太紧,应对变化的能力有限。比如以后将TextBox换成其它形式的控件,一旦并不支持TextChanged事件,原来的代码就得修改。
2、代码重用率低,如果其它界面上也需要类似的需求,只能把本页面Xaml、Xaml.cs的代码复制一遍,如果以后需求有变化,更增加了维护成本。
所以,理想的解决方法,应该是Company类自身能“智能感知”员工的变化,并自动更新工资汇总字段。(即:员工Employee的工资有变化时,应该主动通知Company类。这跟实际公司的运营管理也比较接近,人事给员工调整了工资,肯定会主动通知财务,所以财务肯定也就知道了最新的工资汇总数据。)
这时,双向绑定就再一次体现了这种威力,我们把Company类改造一下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
public
class
Company:INotifyPropertyChanged {
private
ObservableCollection<Employee> _employeeCollection = new
ObservableCollection<Employee>();
/// <summary>
/// 公司的"员工集合"
/// </summary>
public
ObservableCollection<Employee> EmployeeCollection
{
get
{ return
_employeeCollection; }
}
/// <summary>
/// 构造函数
/// </summary>
public
Company()
{
_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;
}
}
private
void
OnPropertyChanged( string
propertyName)
{
if
(PropertyChanged != null )
{
PropertyChanged( this , new
PropertyChangedEventArgs(propertyName));
}
}
public
event
PropertyChangedEventHandler PropertyChanged;
}
|
这里,我们充分利用了INotifyPropertyChanged接口的PropertyChanged事件,以及INotifyCollectionChanged接口的CollectionChanged事件,实现了自动通知。
这样一来,界面UI部分就轻松多了,只需要简单的绑定即可。
Xaml部分:
Xaml部分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
<UserControl x:Class= "XmlClassSerelizer.MainPage"
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}" >
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header= "姓名" >
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text= "{Binding Name,Mode=TwoWay}"
VerticalAlignment= "Center"
Margin= "1" ></TextBox>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header= "工资" >
<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>
<StackPanel HorizontalAlignment= "Center"
Orientation= "Horizontal"
Margin= "5" >
<Button Click= "AddEmployee"
Padding= "10,1" >+</Button>
</StackPanel>
</StackPanel>
</UserControl>
|
Xaml.cs部分:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
using
System.Windows;
using
System.Windows.Controls;
namespace
XmlClassSerelizer
{
public
partial
class
MainPage : UserControl
{
Company c = new
Company();
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};
c.EmployeeCollection.Add(e1);
c.EmployeeCollection.Add(e2);
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 });
}
}
}
|
运行效果:
http://www.cnblogs.com/yjmyzz/archive/2011/06/26/2090538.html
转载于:https://blog.51cto.com/flydragon0815/752045