• Silverlight:双向绑定综合应用自动更新集合汇总字段


    场景:有一家公司(类名:Company),它有N多员工(类名:Employee)。要在界面上用网格显示所有员工的姓名、工资,并且当操作用户在网格里对员工进行增减或修改其工资时,能自动汇总出员工工资的总和并显示出来。
    员工类 Employee代码如下:
        /// <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代码原型如下:
    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类改造一下:
        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部分:
    <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="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部分:
    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 });
            }
    
           
        }
    }
    
    运行效果:
  • 相关阅读:
    删除commit(暂存区)中的文件(git)
    bower安装使用以及git安装
    compass模块----Utilities----Sprites精灵图合图
    compass模块----Utilities
    compass模块----Helpers
    compass模块
    compass安装
    Sass@规则
    Sass函数--颜色函数--Opacity函数
    Sass函数--颜色函数--HSL函数
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/2090538.html
Copyright © 2020-2023  润新知