• 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();
            }
    
    
        }
    }
    
    示例源码下载:
  • 相关阅读:
    Silverlight之各种线程的操作
    MVVM之Event and Command
    Silverlight之DescriptionViewer
    MVVM之Validation
    蚁群算法(C语言实现)
    最小生成树的prim算法
    关于HashMap、LinkedHashMap与TreeMap
    Slope One :简单高效的协同过滤算法(Collaborative Filtering)——转
    java中使用匿名类重写
    Session学习:防止用户重复提交表单(单态设计模式原子设计模式+MD5技术&Base64算法)
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/2090730.html
Copyright © 2020-2023  润新知