在BindingList的ItemChanging事件中获取已删除的项目

Meg*_*ind 23 c# bindinglist inotifypropertychanged

我在我的应用程序中使用绑定列表以及ItemChanged事件.

有什么办法可以知道ItemChanged事件中以前的属性值.目前我正在添加一个名为'OldValue'的独立属性来实现此目的.

有没有办法知道项目更改事件中已删除的项目.我无法找到任何方法来知道哪个项目已从列表中删除.

Thr*_*ent 40

如果我理解正确,您想获取有关从绑定列表中删除的项目的信息.

我认为最简单的方法是创建自己的绑定列表,该列表派生自绑定列表.

在你内部你将有RemoveItem方法覆盖,所以在从绑定列表中删除项目之前,你将能够触发包含将要删除的项目的事件.

public class myBindingList<myInt> : BindingList<myInt>
{
        protected override void RemoveItem(int itemIndex)
        {
            //itemIndex = index of item which is going to be removed
            //get item from binding list at itemIndex position
            myInt deletedItem = this.Items[itemIndex];

            if (BeforeRemove != null)
            {
                //raise event containing item which is going to be removed
                BeforeRemove(deletedItem);
            }

            //remove item from list
            base.RemoveItem(itemIndex);
        }

        public delegate void myIntDelegate(myInt deletedItem);
        public event myIntDelegate BeforeRemove;
    }
Run Code Online (Sandbox Code Playgroud)

为了示例,我创建了类型myInt实现INotifyPropertyChanged - 接口只是在添加/删除绑定列表中的元素后刷新dataGridView.

public class myInt : INotifyPropertyChanged
    {
        public myInt(int myIntVal)
        {
            myIntProp = myIntVal;
        }
        private int iMyInt;
        public int myIntProp {
            get
            {
                return iMyInt;
            }
            set
            {
                iMyInt = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("myIntProp"));
                }
            } 
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }
Run Code Online (Sandbox Code Playgroud)

我正在使用int初始化绑定列表(确切地说是myInts),然后我将绑定列表绑定到dataGridView(用于演示目的)并订阅我的BeforeRemove事件.

bindingList = new myBindingList<myInt>();
        bindingList.Add(new myInt(8));
        bindingList.Add(new myInt(9));
        bindingList.Add(new myInt(11));
        bindingList.Add(new myInt(12));

        dataGridView1.DataSource = bindingList;
        bindingList.BeforeRemove += bindingList_BeforeRemove;
Run Code Online (Sandbox Code Playgroud)

如果引发BeforeRemove事件,我有删除的项目

 void bindingList_BeforeRemove(Form1.myInt deletedItem)
    {
        MessageBox.Show("You've just deleted item with value " + deletedItem.myIntProp.ToString());
    }
Run Code Online (Sandbox Code Playgroud)

下面是整个示例代码(在表单上删除3个按钮和dataGridView) - 按钮1初始化绑定列表,按钮2添加项目到列表,按钮3从登记列表中删除项目

在删除之前

删除后

删除

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace bindinglist
{
public partial class Form1 : Form
{
    myBindingList<myInt> bindingList;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        bindingList = new myBindingList<myInt>();
        bindingList.Add(new myInt(8));
        bindingList.Add(new myInt(9));
        bindingList.Add(new myInt(11));
        bindingList.Add(new myInt(12));

        dataGridView1.DataSource = bindingList;
        bindingList.BeforeRemove += bindingList_BeforeRemove;
    }

    void bindingList_BeforeRemove(Form1.myInt deletedItem)
    {
        MessageBox.Show("You've just deleted item with value " + deletedItem.myIntProp.ToString());
    }


    private void button2_Click(object sender, EventArgs e)
    {
        bindingList.Add(new myInt(13));
    }

    private void button3_Click(object sender, EventArgs e)
    {
        bindingList.RemoveAt(dataGridView1.SelectedRows[0].Index);
    }

    public class myInt : INotifyPropertyChanged
    {
        public myInt(int myIntVal)
        {
            myIntProp = myIntVal;
        }
        private int iMyInt;
        public int myIntProp {
            get
            {
                return iMyInt;
            }
            set
            {
                iMyInt = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("myIntProp"));
                }
            } 
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class myBindingList<myInt> : BindingList<myInt>
    {
        protected override void RemoveItem(int itemIndex)
        {
            myInt deletedItem = this.Items[itemIndex];

            if (BeforeRemove != null)
            {
                BeforeRemove(deletedItem);
            }

            base.RemoveItem(itemIndex);
        }

        public delegate void myIntDelegate(myInt deletedItem);
        public event myIntDelegate BeforeRemove;
    }
}
}
Run Code Online (Sandbox Code Playgroud)

向评论致敬

"问题的另一部分是=>有没有办法知道列表中更改的项目的旧值?在ListChangedEvent中不共享任何内容"

要查看项的旧值,可以覆盖SetItem方法

protected override void SetItem(int index, myInt item)
        {
            //here we still have old value at index
            myInt oldMyInt = this.Items[index];
            //new value
            myInt newMyInt = item;

            if (myIntOldNew != null)
            {
                //raise event
                myIntOldNew(oldMyInt, newMyInt);
            }

            //update item at index position
            base.SetItem(index, item);
        }
Run Code Online (Sandbox Code Playgroud)

当指定索引处的对象发生更改时会触发它,就像这样

bindingList[dataGridView1.SelectedRows[0].Index] = new myInt(new Random().Next());
Run Code Online (Sandbox Code Playgroud)

如果您尝试直接修改项目的属性,那么棘手的部分是

bindingList[dataGridView1.SelectedRows[0].Index].myIntProp = new Random().Next();
Run Code Online (Sandbox Code Playgroud)

SetItem 不会触发,它必须被整个对象替换掉.

所以我们需要另一个委托和事件来处理这个问题

public delegate void myIntDelegateChanged(myInt oldItem, myInt newItem);
public event myIntDelegateChanged myIntOldNew;
Run Code Online (Sandbox Code Playgroud)

然后我们可以订阅这个

bindingList.myIntOldNew += bindingList_myIntOldNew;
Run Code Online (Sandbox Code Playgroud)

并处理它

void bindingList_myIntOldNew(Form1.myInt oldItem, Form1.myInt newItem)
{
    MessageBox.Show("You've just CHANGED item with value " + oldItem.myIntProp.ToString() + " to " + newItem.myIntProp.ToString());
}
Run Code Online (Sandbox Code Playgroud)

之前 事件提出 变

更新的代码(需要4个按钮,第4个修改所选项目)

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace bindinglist
{
public partial class Form1 : Form
{
    myBindingList<myInt> bindingList;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        bindingList = new myBindingList<myInt>();
        bindingList.Add(new myInt(8));
        bindingList.Add(new myInt(9));
        bindingList.Add(new myInt(11));
        bindingList.Add(new myInt(12));

        dataGridView1.DataSource = bindingList;
        bindingList.BeforeRemove += bindingList_BeforeRemove;
        bindingList.myIntOldNew += bindingList_myIntOldNew;
    }

    void bindingList_myIntOldNew(Form1.myInt oldItem, Form1.myInt newItem)
    {
        MessageBox.Show("You've just CHANGED item with value " + oldItem.myIntProp.ToString() + " to " + newItem.myIntProp.ToString());
    }



    void bindingList_BeforeRemove(Form1.myInt deletedItem)
    {
        MessageBox.Show("You've just deleted item with value " + deletedItem.myIntProp.ToString());
    }


    private void button2_Click(object sender, EventArgs e)
    {
        bindingList.Add(new myInt(13));
    }

    private void button3_Click(object sender, EventArgs e)
    {
        bindingList.RemoveAt(dataGridView1.SelectedRows[0].Index);
    }

    public class myInt : INotifyPropertyChanged
    {
        public myInt(int myIntVal)
        {
            myIntProp = myIntVal;
        }
        private int iMyInt;
        public int myIntProp {
            get
            {
                return iMyInt;
            }
            set
            {
                iMyInt = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("myIntProp"));
                }
            } 
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class myBindingList<myInt> : BindingList<myInt>
    {
        protected override void SetItem(int index, myInt item)
        {
            myInt oldMyInt = this.Items[index];
            myInt newMyInt = item;

            if (myIntOldNew != null)
            {
                myIntOldNew(oldMyInt, newMyInt);
            }

            base.SetItem(index, item);
        }

        protected override void RemoveItem(int itemIndex)
        {
            myInt deletedItem = this.Items[itemIndex];

            if (BeforeRemove != null)
            {
                BeforeRemove(deletedItem);
            }

            base.RemoveItem(itemIndex);
        }

        public delegate void myIntDelegateChanged(myInt oldItem, myInt newItem);
        public event myIntDelegateChanged myIntOldNew;

        public delegate void myIntDelegate(myInt deletedItem);
        public event myIntDelegate BeforeRemove;


    }

    private void button4_Click(object sender, EventArgs e)
    {
        bindingList[dataGridView1.SelectedRows[0].Index] = new myInt(new Random().Next());
    }
}
}
Run Code Online (Sandbox Code Playgroud)


小智 6

解决此问题的另一种方法是使用BindingList包装ObservableCollection.这段代码适合我 -

    public void X()
    {
        ObservableCollection<object> oc = new ObservableCollection<object>();
        BindingList<object> bl = new BindingList<object>(oc);
        oc.CollectionChanged += oc_CollectionChanged;
        bl.Add(new object());
        bl.RemoveAt(0);
    }

    void oc_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            foreach (object o in e.OldItems)
            {
                //o was deleted
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)