You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

菜谱应用食材编辑功能遇System.NullReferenceException问题求助

问题描述

我正在开发一个菜谱应用的食材编辑功能,主窗体可以打开「添加食材」窗体,这个「添加食材」窗体又能打开「编辑选中食材」窗体,用来修改数组中选中的食材。但当我尝试获取选中项的索引,想用「编辑食材」窗体的输入替换原有内容时,抛出了异常:

System.NullReferenceException: 'Object reference not set to an instance of an object.'
System.Windows.Forms.ListBox.SelectedItem.get returned null.

我知道这个异常是因为打开其他窗体后,当前窗体的ListBox选中项变成了null。我试过在打开编辑窗体前获取索引,但这个值莫名其妙丢失了。相关代码如下:

private void edit_ingredients_btn_Click(object sender, EventArgs e)
{
    openChange();
}
private void openChange()
{
    if (ingredients_list.SelectedItem != null)
    {
        changeIngredient ingredientChange = new changeIngredient();
        ingredientChange.Show();
    }
    else
    {
        MessageBox.Show("Please select an ingredient to continue");
    }
}
private int findItemToEdit()
{
    string selectedItem = ingredients_list.SelectedItem.ToString();
    int elementSelected = Array.IndexOf(currIngredients, selectedItem);
    return elementSelected;
}
public void IngredientName(string strNewName)
{
    string strEdit = strNewName;
    ingredientEdit(strEdit);
    
}

private void ingredientEdit(string strEdit)
{
    int index = findItemToEdit();
    currIngredients[index] = strEdit;
    ingredients_list.Items.Add(currIngredients[index]);
}
解决方案

核心问题是打开编辑窗体后,原窗体ListBox的选中状态丢失,等到调用findItemToEdit时SelectedItem已经是null。解决思路是在打开编辑窗体前就把选中项的索引和数据传递给编辑窗体,而非编辑完成后再回头读取。

步骤1:修改编辑窗体(changeIngredient),添加数据接收和回调逻辑

在changeIngredient窗体中添加属性接收选中食材的索引、原名称,同时定义事件用于通知原窗体更新数据:

public partial class changeIngredient : Form
{
    // 接收选中食材的索引和原名称
    public int SelectedIngredientIndex { get; set; }
    public string OriginalIngredientName { get; set; }

    // 定义委托,用于通知原窗体更新食材
    public delegate void IngredientUpdatedHandler(int index, string newName);
    public event IngredientUpdatedHandler OnIngredientUpdated;

    public changeIngredient()
    {
        InitializeComponent();
    }

    // 编辑窗体的确认按钮点击事件
    private void confirm_btn_Click(object sender, EventArgs e)
    {
        string newName = ingredient_name_textbox.Text.Trim();
        if (!string.IsNullOrEmpty(newName))
        {
            // 通知原窗体更新数据
            OnIngredientUpdated?.Invoke(SelectedIngredientIndex, newName);
            this.Close();
        }
        else
        {
            MessageBox.Show("请输入食材名称");
        }
    }
}

步骤2:修改原窗体的openChange方法,传递数据并订阅事件

打开编辑窗体时,立即获取选中项的索引和内容,传递给编辑窗体,同时订阅编辑完成的事件,在回调里更新数组和ListBox:

private void openChange()
{
    if (ingredients_list.SelectedItem != null)
    {
        // 提前获取选中项的索引和内容
        string selectedItem = ingredients_list.SelectedItem.ToString();
        int selectedIndex = Array.IndexOf(currIngredients, selectedItem);

        changeIngredient ingredientChange = new changeIngredient();
        // 传递数据给编辑窗体
        ingredientChange.SelectedIngredientIndex = selectedIndex;
        ingredientChange.OriginalIngredientName = selectedItem;
        // 设置编辑框默认值为原食材名称
        ingredientChange.ingredient_name_textbox.Text = selectedItem;

        // 订阅编辑完成事件
        ingredientChange.OnIngredientUpdated += IngredientChange_OnIngredientUpdated;

        // 用ShowDialog模态打开,避免原窗体失去焦点后选中状态丢失
        ingredientChange.ShowDialog();
    }
    else
    {
        MessageBox.Show("请先选择要编辑的食材");
    }
}

// 编辑完成后的回调,更新数组和ListBox
private void IngredientChange_OnIngredientUpdated(int index, string newName)
{
    // 更新数组
    currIngredients[index] = newName;
    // 更新ListBox对应项(不是添加新项)
    ingredients_list.Items[index] = newName;
}

步骤3:移除冗余方法

原有的findItemToEdit、IngredientName、ingredientEdit方法已经不需要,可以直接删除,避免冗余和潜在错误。

关键说明

  • 用ShowDialog替代Show:模态打开编辑窗体,原窗体无法获得焦点,从根源上避免ListBox选中状态丢失的问题。
  • 提前传递数据:在打开编辑窗体时就把需要的索引和名称传递过去,不需要后续再从原窗体读取,彻底解决SelectedItem为null的异常。
  • 事件回调解耦:通过事件通知原窗体更新数据,避免窗体间直接操作控件的耦合问题,代码更易维护。

内容的提问来源于stack exchange,提问作者Kyhro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 10:53:36