草庐IT

c# - 在 BindingList 的 ItemChanging 事件中获取 Deleted Item

coder 2023-07-11 原文

我在我的应用程序中使用绑定(bind)列表以及 ItemChanged 事件。

有什么方法可以让我知道 ItemChanged 事件中属性的先前值。目前,我正在添加一个名为“OldValue”的单独属性来实现此目的。

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

最佳答案

如果我没理解错的话,你想获取有关已从绑定(bind)列表中删除的项目的信息。

我认为最简单的方法是创建您自己的绑定(bind)列表,该绑定(bind)列表派生自绑定(bind)列表。

在内部,您将覆盖 RemoveItem 方法,因此在从绑定(bind)列表中删除项目之前,您将能够触发包含将要删除的项目的事件。

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;
}

为了示例,我创建了实现 INotifyPropertyChanged 的​​类型 myInt - 接口(interface)只是为了在从绑定(bind)列表中添加/删除元素后刷新 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;
}

我正在使用 int 初始化绑定(bind)列表(准确地说是 myInts),然后我将绑定(bind)列表绑定(bind)到 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;

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

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

下面是整个示例代码(在表单上放置 3 个按钮和 dataGridView)- 按钮 1 初始化绑定(bind)列表,按钮 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;
        }
    }
}

回复评论

“问题的另一部分是 => 有没有办法知道列表中更改的项目的旧值?在 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);
}

当指定索引处的对象发生更改时触发,如下所示

bindingList[dataGridView1.SelectedRows[0].Index] = new myInt(new Random().Next());

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

bindingList[dataGridView1.SelectedRows[0].Index].myIntProp = new Random().Next();

SetItem 不会触发,必须替换整个对象。

所以我们需要另一个委托(delegate)和事件来处理这个

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

然后我们可以订阅这个

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());
}

更新代码(需要 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());
        }
    }
}

关于c# - 在 BindingList 的 ItemChanging 事件中获取 Deleted Item,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23339233/

有关c# - 在 BindingList 的 ItemChanging 事件中获取 Deleted Item的更多相关文章

  1. ruby - 简单获取法拉第超时 - 2

    有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url

  2. ruby - 从 Ruby 中的主机名获取 IP 地址 - 2

    我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge

  3. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  4. ruby-on-rails - 获取 inf-ruby 以使用 ruby​​ 版本管理器 (rvm) - 2

    我安装了ruby​​版本管理器,并将RVM安装的ruby​​实现设置为默认值,这样'哪个ruby'显示'~/.rvm/ruby-1.8.6-p383/bin/ruby'但是当我在emacs中打开inf-ruby缓冲区时,它使用安装在/usr/bin中的ruby​​。有没有办法让emacs像shell一样尊重ruby​​的路径?谢谢! 最佳答案 我创建了一个emacs扩展来将rvm集成到emacs中。如果您有兴趣,可以在这里获取:http://github.com/senny/rvm.el

  5. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  6. Ruby 从大范围中获取第 n 个项目 - 2

    假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit

  7. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  8. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  9. ruby - 没有类方法获取 Ruby 类名 - 2

    如何在Ruby中获取BasicObject实例的类名?例如,假设我有这个:classMyObjectSystem我怎样才能使这段代码成功?编辑:我发现Object的实例方法class被定义为returnrb_class_real(CLASS_OF(obj));。有什么方法可以从Ruby中使用它? 最佳答案 我花了一些时间研究irb并想出了这个:classBasicObjectdefclassklass=class这将为任何从BasicObject继承的对象提供一个#class您可以调用的方法。编辑评论中要求的进一步解释:假设你有对象

  10. ruby-on-rails - 如何在 Gem 中获取 Rails 应用程序的根目录 - 2

    是否可以在应用程序中包含的gem代码中知道应用程序的Rails文件系统根目录?这是gem来源的示例:moduleMyGemdefself.included(base)putsRails.root#returnnilendendActionController::Base.send:include,MyGem谢谢,抱歉我的英语不好 最佳答案 我发现解决类似问题的解决方案是使用railtie初始化程序包含我的模块。所以,在你的/lib/mygem/railtie.rbmoduleMyGemclassRailtie使用此代码,您的模块将在

随机推荐