Запрет на срабатывание события listBox

В общем, такая проблема. Есть ListBox1, в Item которого отображаются поле объектов, при выборе одного Item в ListBox2 отображаются остальные поля объекта. Происходит это через событие listBox1_SelectedIndexChanged. Также нужно оформить возможность удаления объекта, через нажатие клавиши "Delete". Это сделал в listBox1_KeyUp. Но при удалении объекта выбрасывается NullReferenceExcaption. Срабатывает событие KeyUp, а после него SelectedIndexChanged, и во втором получается, что он пытает отобразить не существующий объект (я так понял). Теперь сижу и думаю, как это исправить. Буду благодарен за подсказку.

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
           
 var newlist = list.questionList;

       if ((newQuestion.questions == "")&&(newQuestion.rightAnswer=="")&&(newQuestion.answer.Count==0))
            {
                listBox2.Items.Clear();
                
                foreach (var obj in newlist)
                {

                    if (obj.questions == listBox1.SelectedItem.ToString())
                    {
                        foreach (var obj2 in obj.answer)
                        {
                            listBox2.Items.Add(obj2);
                        }
                        listBox2.Items.Add(obj.rightAnswer);

                    }
                    
                }
        
 private void listBox1_KeyUp(object sender, KeyEventArgs e)
        {

            if (e.KeyValue.ToString() == "46")
            {
                var newlist = list.questionList;
                foreach (var obj in newlist)
                {
                    if (listBox1.SelectedItem.ToString() == obj.questions)
                    {
                        listBox1.Items.Remove(listBox1.SelectedItem);
                        list.questionList.Remove(obj);
                        MessageBox.Show("Sucsess");

                    }
                }

            }
        }


 public class Question

    {
        public string questions;

        public List<string> answer;

        public string rightAnswer;

        public Question()
        {
            this.questions = "";

            this.answer = new List<string>();

            this.rightAnswer = "";
        }
        public override string ToString()
        {
            string result = "";
            foreach (var obj in answer)
            {
                result += "\n"+obj+"\n";
            }
            return $"Question\n{questions}\nanswer\n{result}\nright answer\n{rightAnswer}";
        }
    }

    [Serializable]
    public class QuestionList
    {
      public string TestName { get; set; }
      public int TestTime { get; set; } 
      public int PassMark { get; set; }
      public List<Question> questionList;
      
      public  QuestionList()
        {
            questionList = new List<Question>();
            TestName = "";
            TestTime = 0;
            PassMark = 0;
        }
        public void AddQuestion(Question obj)
        {
            questionList.Add(obj);
        }

Ответы (1 шт):

Автор решения: rdorn

Отключить возникновение события у вас не получится, это не предусмотрено.

Но у вашей проблемы есть вполне очевидное решение: добавьте необходимую проверку в обработчик listBox1_SelectedIndexChanged и, если объект был удален, просто завершите обработчик не пытаясь получить данные из несуществующего объекта.

Но вообще вы идете не тем путем в построении приложения на WinForms. Я понимаю. что все примеры кода выглядят примерно так, но не стоит следовать им до буквы. Иногда стоит заглянуть в документацию немного глубже. Я не могу понять из приведенного кода, как должно работать ваше приложение в целом, хотя и догадываюсь, поэтому посоветовать как исправить вашу модель данных я не могу, это в любом случае будет "угадайка". Но, для примера, я набросал простенькую форму, которая демонстрирует как можно сделать проще все то, что есть в приведенном вами фрагменте кода. Модель данных разумеется упрощена до предела, но я думаю будет несложно расширить ее необходимыми вам данными после того как разберетесь как работает мой пример. Ну и вопросы новые появятся, только уже другие.

//модель отображаемого элемента
public class ItemList
{
    public BindingList<Item> Items { get; } = new BindingList<Item>();
}

public class Item
{
    public string Name { get; set; }
    public BindingList<string> Details { get; } = new BindingList<string>();
}

//собственно форма
public partial class Form1 : Form
{
    private ListBox listBox2 = new ListBox();
    private ListBox listBox1 = new ListBox();
    private ItemList model = new ItemList();

    public Form1()
    {
        Controls.Add(listBox2);
        Controls.Add(listBox1);
        listBox1.Dock = DockStyle.Left;
        listBox2.Dock = DockStyle.Fill;
        //указываем какое свойство необходимо отображать в списке
        listBox1.DisplayMember = "Name";
        //указываем откуда брать элементы списка
        listBox1.DataSource = model.Items;
        listBox1.SelectedIndexChanged += ListBox1_SelectedIndexChanged;
        listBox1.KeyUp += ListBox1_KeyUp;
        for (int i = 1; i < 10; i++)
        {
            var item = new Item();
            item.Name = $"item{i}";
            item.Details.AllowEdit = true;
            for (int j = 1; j < 5; j++)
            {
                item.Details.Add($"i{i}_d{j}");
            }
                model.Items.Add(item);
        }
    }

    private void ListBox1_SelectedIndexChanged(object sender, EventArgs e)
    {
        var lb = sender as ListBox;
        if (lb.SelectedItem != null)
        {
            //При наличии выбранного элемента задаем источник данных для ListBox2
            //т.к. ListBox2 будет отображать список простых строк, то имя
            //отображаемого свойства для него можно не указывать
            listBox2.DataSource = (lb.SelectedItem as Item).Details;
        }
        else
        {
            //При отсутствии выбранного элемента очищаем источник данных ListBox2
            listBox2.DataSource = null;
        }
    }

    private void ListBox1_KeyUp(object sender, KeyEventArgs e)
    {
        var lb = sender as ListBox;
        if (e.KeyCode == Keys.Delete && lb.SelectedItem != null)
        {
            //удаление производится не из ListBox, а из его источника данных
            (lb.DataSource as IList<Item>).Remove(lb.SelectedItem as Item);
        }
    }
}

Из дополнительного советую почитать про привязку данных (Data Bining) в WinForms и паттерн MVP. В текущем примере использована только привязка данных. Единственный контрол WinForms, требующий ручного заполнения элементами - TreeView, но и эта проблема решается с помощью паттерна MVP.

→ Ссылка