C#中监听List中成员值的变化

qunser 2013-09-27 04:40:05
请问C#中如何实现在List<T>中成员的值发生变化的时候,触发一个事件?
...全文
3476 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
机器人 2013-09-29
  • 打赏
  • 举报
回复
大家都用wpf的话,这种问题自然就熟悉了
小托尼 2013-09-29
  • 打赏
  • 举报
回复
引用 4 楼 bdmh 的回复:
我的做法是,新建一个类继承自List<T>,list的变化无非就是add,insert,remove,clear等,所以覆盖这些事件,并触发某个事件
对于问题本身,SP大神的DEMO已经完美解决。。 本人照版主的意思实现了下,(虽然并不是这个问题的答案),多写写总是好的
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ExtendList
{
    public delegate void ListChangedEventHandler<T>(object sender);

    public class MyList<T> : List<T>
    {
        private int _count;

        public String Action { get; set; }

        private int MCount
        {
            get { return _count; }
            set
            {
                if (_count != value)
                {
                    _count = this.Count;
                    DoListChangedEvent();
                }
            }
        }

        public event ListChangedEventHandler<T> ListChanged;

        private void DoListChangedEvent()
        {
            if (this.ListChanged != null)
                this.ListChanged(this);
        }

        public new void Add(T t)
        {
            base.Add(t);
            this.Action = "Add";
            MCount++;
        }

        public new void Remove(T t)
        {
            base.Remove(t);
            this.Action = "Remove";
            MCount--;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyList<int> mylist = new MyList<int>();

            mylist.ListChanged += List_CollectionChanged<int>;
            mylist.ListChanged += List_SummaryChanged<int>;

            mylist.Add(1);
            mylist.Add(2);

            mylist.Remove(1);

            Console.ReadKey();
        }

        static void List_CollectionChanged<T>(object sender)
        {
            Console.Write("{0} an item. Current items: {1} \n", ((MyList<T>)sender).Action, String.Join(" ", (MyList<T>)sender));
        }

        static void List_SummaryChanged<T>(object sender)
        {
            Console.Write("*** {0} an item. Current summary: {1} \n", ((MyList<T>)sender).Action, ((MyList<T>)sender).Sum(item => int.Parse(item.ToString())));
        }
    }
}
qunser 2013-09-29
  • 打赏
  • 举报
回复
引用 16 楼 sp1234 的回复:
给你写个demo:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace ConsoleApplication1
{
    class Program
    {
        private static ObservableCollection<DataType> List = new ObservableCollection<DataType>();

        static void Main(string[] args)
        {
            List.CollectionChanged += List_CollectionChanged;
            List.Add(new DataType { Fa = "aaa", Fb = 1 });
            List.Add(new DataType { Fa = "bbb", Fb = 2 });
            List.Add(new DataType { Fa = "ccc", Fb = 3 });
            List.Add(new DataType { Fa = "ddd", Fb = 4 });
            List[3].Fb += 100;  //这个对象修改时,可以在方法obj_PropertyChanged中捕获。
            Console.ReadKey();
        }

        static void List_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                var obj = (DataType)e.NewItems[0];
                obj.PropertyChanged += obj_PropertyChanged;
            }
        }

        static void obj_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var obj = (DataType)sender;
            Console.WriteLine("Fa={0}, Fb={1}", obj.Fa, obj.Fb);
        }

    }


    public class DataType : INotifyPropertyChanged
    {
        private string _Fa;

        public string Fa
        {
            get { return _Fa; }
            set
            {
                if (_Fa != value)
                {
                    _Fa = value;
                    RaisePropertyChangedEvent("Fa");
                }
            }
        }

        private int _Fb;

        public int Fb
        {
            get { return _Fb; }
            set
            {
                if (_Fb != value)
                {
                    _Fb = value;
                    RaisePropertyChangedEvent("Fb");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChangedEvent(string name)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
}
非常感谢您的热心帮助!有您这样的大神真是程序员界的幸事啊! 问题已经搞定了,通过对比,我发现监控List<T>的代价相对有点高,还是直接在TextBox层解决了,通过其他方法遍历出了所有的TextBox,为所有的TextBox绑定了事件,问题圆满解决。 再次感谢!
qunser 2013-09-29
  • 打赏
  • 举报
回复
引用 22 楼 iamwangshao 的回复:
[quote=引用 4 楼 bdmh 的回复:] 我的做法是,新建一个类继承自List<T>,list的变化无非就是add,insert,remove,clear等,所以覆盖这些事件,并触发某个事件
对于问题本身,SP大神的DEMO已经完美解决。。 本人照版主的意思实现了下,(虽然并不是这个问题的答案),多写写总是好的
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ExtendList
{
    public delegate void ListChangedEventHandler<T>(object sender);

    public class MyList<T> : List<T>
    {
        private int _count;

        public String Action { get; set; }

        private int MCount
        {
            get { return _count; }
            set
            {
                if (_count != value)
                {
                    _count = this.Count;
                    DoListChangedEvent();
                }
            }
        }

        public event ListChangedEventHandler<T> ListChanged;

        private void DoListChangedEvent()
        {
            if (this.ListChanged != null)
                this.ListChanged(this);
        }

        public new void Add(T t)
        {
            base.Add(t);
            this.Action = "Add";
            MCount++;
        }

        public new void Remove(T t)
        {
            base.Remove(t);
            this.Action = "Remove";
            MCount--;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyList<int> mylist = new MyList<int>();

            mylist.ListChanged += List_CollectionChanged<int>;
            mylist.ListChanged += List_SummaryChanged<int>;

            mylist.Add(1);
            mylist.Add(2);

            mylist.Remove(1);

            Console.ReadKey();
        }

        static void List_CollectionChanged<T>(object sender)
        {
            Console.Write("{0} an item. Current items: {1} \n", ((MyList<T>)sender).Action, String.Join(" ", (MyList<T>)sender));
        }

        static void List_SummaryChanged<T>(object sender)
        {
            Console.Write("*** {0} an item. Current summary: {1} \n", ((MyList<T>)sender).Action, ((MyList<T>)sender).Sum(item => int.Parse(item.ToString())));
        }
    }
}
[/quote] 感谢您的耐心回答,我也学习到了很多管理List<T>的知识 问题已经搞定了,通过对比,我发现监控List<T>的代价相对有点高,还是直接在TextBox层解决了,通过其他方法遍历出了所有的TextBox,为所有的TextBox绑定了事件,问题圆满解决。 再次感谢!
  • 打赏
  • 举报
回复
嗯,第一层捕获时,写的完备一点(写为foreach)更好:
static void List_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
    {
        foreach (DataType obj in e.NewItems)
            obj.PropertyChanged += obj_PropertyChanged;
    }
}
  • 打赏
  • 举报
回复
两个层次,首先你要监听 ObservableCollection<T> 集合的“增加元素”事件。然后,监听这个T对象的属性修改事件。
  • 打赏
  • 举报
回复 1
给你写个demo:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace ConsoleApplication1
{
    class Program
    {
        private static ObservableCollection<DataType> List = new ObservableCollection<DataType>();

        static void Main(string[] args)
        {
            List.CollectionChanged += List_CollectionChanged;
            List.Add(new DataType { Fa = "aaa", Fb = 1 });
            List.Add(new DataType { Fa = "bbb", Fb = 2 });
            List.Add(new DataType { Fa = "ccc", Fb = 3 });
            List.Add(new DataType { Fa = "ddd", Fb = 4 });
            List[3].Fb += 100;  //这个对象修改时,可以在方法obj_PropertyChanged中捕获。
            Console.ReadKey();
        }

        static void List_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
            {
                var obj = (DataType)e.NewItems[0];
                obj.PropertyChanged += obj_PropertyChanged;
            }
        }

        static void obj_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var obj = (DataType)sender;
            Console.WriteLine("Fa={0}, Fb={1}", obj.Fa, obj.Fb);
        }

    }


    public class DataType : INotifyPropertyChanged
    {
        private string _Fa;

        public string Fa
        {
            get { return _Fa; }
            set
            {
                if (_Fa != value)
                {
                    _Fa = value;
                    RaisePropertyChangedEvent("Fa");
                }
            }
        }

        private int _Fb;

        public int Fb
        {
            get { return _Fb; }
            set
            {
                if (_Fb != value)
                {
                    _Fb = value;
                    RaisePropertyChangedEvent("Fb");
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void RaisePropertyChangedEvent(string name)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }
}
小D2013 2013-09-27
  • 打赏
  • 举报
回复
把textbox的 textchanged 事件注册到同一个处理程序
_小黑_ 2013-09-27
  • 打赏
  • 举报
回复
不好意思 题目理解错了
_小黑_ 2013-09-27
  • 打赏
  • 举报
回复
你写一个控件类 把 text 付给 你写的这个类,我之前 也写过相同的东西

private Control[] goods_HsCode = new Control[2];
        /// <summary>
        /// HS编码
        /// </summary>
        public Control[] Goods_HsCode
        {
            get { return goods_HsCode; }
            set { goods_HsCode = value; }
        }
//在你的窗体加载事件中 给控件类的属性赋值
customsInspectionControl.Goods_HsCode[0] = lblGoods_HsCode;
            customsInspectionControl.Goods_HsCode[1] = txtGoods_HsCode;//HS编码
/// <summary>
        /// 此方法用于在弹出商品种类的时候调用中调用,
        /// 防止用户改变窗体上文本框的值时我不能及时获取,只有调用此方法才获取修改后的值
        /// 因为商品的值是通过list集合穿来的,而修改只是修改控件属性的值,调用此方法把控件的值赋给list集合对应的值
        /// </summary>
        /// <param name="customsInspectionControl"></param>
        public static void GoodsUpdateValue(CustomsInspectionControl customsInspectionControl) 
        {
            if (customsInspectionControl.ListQuery_GoodsInfoInspectionFJ.Count > 0)
            {
                customsInspectionControl.ListQuery_GoodsInfoInspectionFJ[customsInspectionControl.GoodsPage].MillWorkPlant = customsInspectionControl.MillworkPlant[1].Text;
                customsInspectionControl.ListQuery_GoodsInfoInspectionFJ[customsInspectionControl.GoodsPage].Goods_HsCode = customsInspectionControl.Goods_HsCode[1].Text;
            }
        }

一个存储 你的lable 另一个存储 text
lhx527099095 2013-09-27
  • 打赏
  • 举报
回复
引用 11 楼 qunser 的回复:
[quote=引用 9 楼 gomoku 的回复:] [quote=引用 3 楼 gomoku 的回复:] 你可以用BindingList<T>,前提是这个T必须实现INotifyPropertyChanged接口。
T必须实现INotifyPropertyChanged接口[/quote] INotifyPropertyChanged是为了实现当List<T>或ObservableCollection<T>中的值变化时,能实时在UI显示,我的问题就是,当他通知UI说值已经变化的时候,同时通知一下我(或我用什么方法截取到),好让我触发其他的事件?[/quote] INotifyPropertyChanged 接口里面有事件的啊 你怎么实现的接口。。。。。 仔细看下接口的定义代码吧 呵呵
qunser 2013-09-27
  • 打赏
  • 举报
回复
引用 9 楼 gomoku 的回复:
[quote=引用 3 楼 gomoku 的回复:] 你可以用BindingList<T>,前提是这个T必须实现INotifyPropertyChanged接口。
T必须实现INotifyPropertyChanged接口[/quote] INotifyPropertyChanged是为了实现当List<T>或ObservableCollection<T>中的值变化时,能实时在UI显示,我的问题就是,当他通知UI说值已经变化的时候,同时通知一下我(或我用什么方法截取到),好让我触发其他的事件?
  • 打赏
  • 举报
回复
引用 8 楼 qunser 的回复:
[quote=引用 7 楼 gomoku 的回复:] WPF,则用5楼dongxinxi朋友建议的ObservableCollection<T>。
用ObservableCollection<T>也是同样的问题, 在注册的时候可以监听PropertyChanged,但是如何监听这个集合对象内部成员值的变化? 当内部成员值变化时,他会实时通知界面(我用List<T>也实现了),但我用什么方法可以截取到值变化了?以便我触发其他事件? 设置UpdateSourceTrigger为PropertyChanged,也不会响应啊, PropertyChangedCallback和CoerceValueCallback都没有相应[/quote] 可以自定义一个事件,比如event EventHandler ItemTextChanged 给那些要监视的 textBox.TextChanged += (obj, evt) => { if(this.ItemTextChanged != null) this.ItemTextChanged(textBox, EventArgs.Empty); } 当它们任何一个Text变化了都会触发ItemTextChanged,若需要其他参数自己重新定义事件参数类
gomoku 2013-09-27
  • 打赏
  • 举报
回复
引用 3 楼 gomoku 的回复:
你可以用BindingList<T>,前提是这个T必须实现INotifyPropertyChanged接口。
T必须实现INotifyPropertyChanged接口
qunser 2013-09-27
  • 打赏
  • 举报
回复
引用 7 楼 gomoku 的回复:
WPF,则用5楼dongxinxi朋友建议的ObservableCollection<T>。
用ObservableCollection<T>也是同样的问题, 在注册的时候可以监听PropertyChanged,但是如何监听这个集合对象内部成员值的变化? 当内部成员值变化时,他会实时通知界面(我用List<T>也实现了),但我用什么方法可以截取到值变化了?以便我触发其他事件? 设置UpdateSourceTrigger为PropertyChanged,也不会响应啊, PropertyChangedCallback和CoerceValueCallback都没有相应
gomoku 2013-09-27
  • 打赏
  • 举报
回复
WPF,则用5楼dongxinxi朋友建议的ObservableCollection<T>。
qunser 2013-09-27
  • 打赏
  • 举报
回复
引用 4 楼 bdmh 的回复:
我的做法是,新建一个类继承自List<T>,list的变化无非就是add,insert,remove,clear等,所以覆盖这些事件,并触发某个事件 new void Add() { base.Add(); DoEvents();//触发自定义事件 }
可能是我的思路有问题,项目是WPF开发的, 我将一组textbox绑定到了这个List<T>上,当textbox的值发生变化时,这个List<T>的值也实时发生了变化,现在的问题就是我想当textbox变化时,触发一些事件,从textbox入手太麻烦了,本来想给所有textbox绑定事件,但用的控件无法遍历出来所有的textbox,一个一个的为textbox添加事件也不现实,只有退后一步,从List<T>着手了。所以List<T>的变化是内部成员的值发生了变化,这个该怎么搞?
bdmh 2013-09-27
  • 打赏
  • 举报
回复
我的做法是,新建一个类继承自List<T>,list的变化无非就是add,insert,remove,clear等,所以覆盖这些事件,并触发某个事件 new void Add() { base.Add(); DoEvents();//触发自定义事件 }
gomoku 2013-09-27
  • 打赏
  • 举报
回复
你可以用BindingList<T>,前提是这个T必须实现INotifyPropertyChanged接口。
加载更多回复(2)

110,533

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧