BindingList の ItemChanging イベントで削除されたアイテムを取得する 質問する

BindingList の ItemChanging イベントで削除されたアイテムを取得する 質問する

私はアプリケーションで、ItemChanged イベントとともに Binding List を使用しています。

ItemChanged イベントのプロパティの以前の値を知る方法はありますか。現在、これを実現するために、「OldValue」という名前の別のプロパティを追加しています。

アイテム変更イベントで削除されたアイテムを知る方法はありますか。リストからどのアイテムが削除されたかを知る方法が見つかりません。

ベストアンサー1

私の理解が正しければ、バインディング リストから削除されたアイテムに関する情報を取得したいということですね。

これを行う最も簡単な方法は、バインディング リストから派生した独自のバインディング リストを作成することだと思います。

内部では 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;
}

例として、INotifyPropertyChanged を実装する myInt 型を作成しました。このインターフェースは、バインディング リストから要素を追加/削除した後に 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 (正確には 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;

BeforeRemoveイベントが発生した場合、削除されたアイテムがあります

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

以下はサンプルコード全体です(フォームに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;
        }
    }
}

コメントへの回答

「質問のもう 1 つの部分は => リスト内で変更された項目の古い値を知る方法はありますか? 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();

アイテムの設定発射しないオブジェクト全体を置き換える必要があります。

そのため、これを処理するために別のデリゲートとイベントが必要になります

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

おすすめ記事