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

时间: 2024-09-15 07:41:30

Silverlight:双向绑定综合应用-多集合的依赖绑定的相关文章

通过实例模拟ASP.NET MVC的Model绑定的机制:集合+字典

在本系列的前面两篇文章(<简单类型+复杂类型>.<数组>)我们通过创建的实例程序模拟了ASP.NET MVC默认使用的DefaultModelBinder对简单类型.复杂类型以及数组对象的Model绑定.现在我们按照相同的方式来分析基于集合和字典类型的Model绑定是如何实现的.[源代码从这里下载] 一.集合 这里的集合指的是除数组和字典之外的所有实现IEnumerable<T>接口的类型.和基于数组的Model绑定类似,ValueProvider可以将多个同名的数据项

DataList绑定到Row[]行集合的问题的方法_实用技巧

当dataList绑定到一个行集合时,直接使用 <%# DataBinder.Eval(Container.DataItem,"fldName") %>时,编译时将会出现 "DataBinder.Eval:"System.Data.DataRow"不包含名称为 fldName 的属性"  的错误 解决办法:将 <%# DataBinder.Eval(Container.DataItem, "fldName")

重新想象 Windows 8 Store Apps (52) - 绑定: 与 Element Model Indexer Style RelativeSource 绑定, 以及绑定中的数据转换

原文:重新想象 Windows 8 Store Apps (52) - 绑定: 与 Element Model Indexer Style RelativeSource 绑定, 以及绑定中的数据转换 [源码下载] 重新想象 Windows 8 Store Apps (52) - 绑定: 与 Element Model Indexer Style RelativeSource 绑定, 以及绑定中的数据转换 作者:webabcd 介绍重新想象 Windows 8 Store Apps 之 绑定 与

省市联动JS能绑定数据库数据么??能绑定的话怎么调数据库数据!!!!

问题描述 省市联动JS能绑定数据库数据么??能绑定的话怎么调数据库数据!!!! 省市联动JS能绑定数据库数据么??能绑定的话怎么调数据库数据!!!! 解决方案 省select可以直接绑定数据,市生成js数组,通过js获取数据中进行option的添加删除 一个简单的DEMO,注意数据的生成 省:<select id=""pro""><option value="""">请选择省</option>

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

场景:有一家公司(类名:Company),它有N多员工(类名:Employee).要在界面上用网格显示所有员工的姓名.工资,并且当操作用户在网格里对员工进行增减或修改其工资时,能自动汇总出员工工资的总和并显示出来. 员工类 Employee代码如下: /// <summary> /// 员工类 /// </summary> public class Employee:INotifyPropertyChanged { private string _name = "&quo

关于silverlight中如何更新(增删改)集合ItemsSource后更新到UI(Listbox、DataGrid等)

请看微软资料 http://msdn.microsoft.com/zh-cn/library/system.windows.controls.itemscontrol.itemssource%28v=vs.95%29.aspx   具体方案为:将ItermsSource设置为实现 INotifyCollectionChanged 接口的对象,以使集合的更改在 ItemsControl 中反映出来. ObservableCollection<T> 类即定义这样的对象,不要贪图方便而使用List&

新浪微博绑定手机时提示手机号码已被绑定怎么办?

  如果手机号已被他人微博绑定,可以先解除手机绑定,用您被绑定的手机号发送短信jcbd(解除绑定的首字母)到1069009009进行解除绑定.解除后,即可在帐号-帐号设置-绑定手机页面,将您的手机号与微博帐号进行绑定了. 绑定地址:http://account.weibo.com/settings/mobile

域名绑定 端口映射-申请了域名并绑定到了nginx,但始终无法通过域名打开网页

问题描述 申请了域名并绑定到了nginx,但始终无法通过域名打开网页 nginx配置如下: 域名在新网申server { listen 80; server_name www.lazer-easy7.space; location / { root html; index index.html index.htm; } } 域名是在新网请的,并且已经解析过了,通过ping www.lazer-easy7.space 也可以看到域名已经解析成我的ip地址. 我是ADSL拨号上网,动态ip,有路由器

js中this绑定问题-javascript中关于this的绑定问题

问题描述 javascript中关于this的绑定问题 var point = { x : 0, y : 0, moveTo : function(x, y) { // 内部函数 var moveX = function(x) { this.x = x;//this 绑定到了哪里? }; // 内部函数 var moveY = function(y) { this.y = y;//this 绑定到了哪里? }; moveX(x); moveY(y); } }; point.moveTo(1, 1