Silverlight: bidirectional binding of integrated applications-automatically update collection summary Fields

Source: Internet
Author: User
Scenario: There is a company with N employees (Class Name: employee ). The name and salary of all employees should be displayed on the page with a grid, and when the operator increases or decreases the employee's salary in the grid, the sum of employees' salaries can be automatically summarized and displayed. The employee-class employee code is as follows:
/// <Summary> /// employee class /// </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 Vo Id onpropertychanged (string propertyname) {If (propertychanged! = NULL) {propertychanged (this, new propertychangedeventargs (propertyname ));}}}
The company code prototype is as follows:
Public class company {private observablecollection <employee> _ employeecollection = new observablecollection <employee> (); /// <summary> /// company's "Employee Collection" /// </Summary> Public observablecollection <employee> employeecollection {get {return _ employeecollection ;}} private void computesalarytotal () {_ salarytotal = _ employeecollection. sum (C => C. salary);} private int _ salarytotal = 0; // <summary> // salary summary /// </Summary> Public int salarytotal {get {computesalarytotal (); return _ salarytotal ;}}}

Conventional solution: You can register the textchanged or lostfocus event on the textbox corresponding to the "salary" field in each row of the grid, and update the sum when the input value changes or loses focus. This is easy to think of, but not elegant, because: 1. Events are bound to the textbox of each line, and in The XAML. code writing on CS is similar to textboxtotal. TEXT = company. salarytotal logic. In this way, the interface logic code is too tightly bound with the UI, and the ability to cope with changes is limited. For example, you can change textbox to another form of control later. Once the textchanged event is not supported, the original code must be modified. 2. The code reuse rate is low. If similar requirements are also required on other interfaces, you can only set the current page's XAML and XAML. the CS code is replicated once. If the requirements change in the future, the maintenance cost will be increased. Therefore, the ideal solution should be that the company class can "intelligently perceive" employee changes and automatically update the salary summary field. (That is, the company class should be notified automatically when the employee's salary changes. This is also close to the actual company's operation and management. After the personnel adjusts the salary for the employee, they will certainly take the initiative to inform the finance, so the finance will certainly know the latest wage summary data .) At this time, the two-way binding once again reflects this power, we will transform the company class:

Public class company: inotifypropertychanged {private observablecollection <employee> _ employeecollection = new observablecollection <employee> (); /// <summary> /// company's "Employee Collection" /// </Summary> Public observablecollection <employee> employeecollection {get {return _ employeecollection ;}} /// <summary> /// constructor /// </Summary> Public Company () {_ employeecollection. collectionchanged + = new notifycollecti Onchangedeventhandler (_ employeecollection_collectionchanged );} /// <summary> /// triggered automatically when an employee has "increased or decreased" /// </Summary> /// <Param name = "sender"> </param>/ // <Param name = "E"> </param> private void _ employeecollection_collectionchanged (Object sender, notifycollectionchangedeventargs e) {// recalculates the sum of wages computesalarytotal (); // when the "salary" attribute of each employee changes, the specified event foreach (VAR item in _ employeecollection) is automatically triggered) {item. propertychanged -= New propertychangedeventhandler (item_propertychanged); item. propertychanged + = new propertychangedeventhandler (item_propertychanged );}} /// <summary> /// call this method automatically when the employee attributes change /// </Summary> /// <Param name = "sender"> </param>/ // <Param name = "E"> </param> private void item_propertychanged (Object sender, propertychangedeventargs e) {// if the "salary" attribute changes, the system automatically recalculates the salary summary if (E. propertyname = "salary") {computes Alarytotal () ;}} private void computesalarytotal () {_ salarytotal = _ employeecollection. sum (C => C. salary); onpropertychanged ("salarytotal"); // After the sum of wages is recalculated, events are broadcast externally so that the UI can be automatically updated} private int _ salarytotal = 0; /// <summary> /// salary 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 ;}
Here, we fully utilize the propertychanged event of the inotifypropertychanged interface and the collectionchanged event of the inotifycollectionchanged interface to implement automatic notification. In this way, the UI is much easier, and you only need to simply bind it.
XAML section:
<Usercontrol X: class = "xmlclassserelizer. 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 = "," name = "datagrid1" verticalignment = "center" itemssource = "{binding employeecollection}"> <SDK: dataGrid. columns> <SDK: Maid header = "name"> <SDK: maid. celltemplate> <datatemplate> <textbox text = "{binding name, mode = twoway} "verticalalignment =" center "margin =" 1 "> </textbox> </datatemplate> </SDK: datagridtemplatecolumn. celltemplate> </SDK: Maid> <SDK: Maid header = ""> <SDK: maid. celltemplate> <datatemplate> <textbox text = "{binding salary, mode = twoway} "verticalalignment =" center "margin =" 1 "> </textbox> </datatemplate> </SDK: datagridtemplatecolumn. celltemplate> </SDK: Maid> <SDK: Maid header = "operation"> <SDK: maid. celltemplate> <datatemplate> <button click = "removeemployee" horizontalalignment = "center" verticalignment = "center" padding = "10, 1">-</button> </datatemplate> </SDK: datagridtemplatecolumn. celltemplate> </SDK: datagridtemplatecolumn> </SDK: DataGrid. columns> </SDK: DataGrid> <stackpanel horizontalalignment = "center" orientation = "horizontal" margin = "5"> <textblock verticalignment = "center"> total salary: </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> </usercontrol>
XAML. CS section:
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 = "zhangsan", salary = 3000 }; employee e2 = new employee () {name =" Li Si ", salary = 4000}; C. employeecollection. add (E1); C. employeecollection. add (E2); this. datacontext = C ;} /// <summary> /// Delete employee /// </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> /// add employee /// </Summary> /// <Param name = "sender"> </param> /// <Param name = "E"> </param> private void addemployee (Object sender, routedeventargs e) {C. employeecollection. add (new employee () {name = "newcomer", salary = 1000 });}}}
Running effect:

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.