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)