You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#中使用<ListBox.ItemTemplate>的Artikel ListBox删除行异常求助

问题排查与解决方案:Artikel窗体ListBox删除操作异常

我来帮你梳理下这个问题——同样的删除逻辑在Lieferant窗体正常运行,但到了Artikel窗体就出警告,结合两个表的结构差异,大概率是ListBox绑定或者参数处理的细节问题,咱们一步步拆开来排查:

1. 先查ListBox.SelectedValue的绑定是否正确

你在Artikel窗体用了<ListBox.ItemTemplate>渲染复杂行,但很可能没给ListBox设置SelectedValuePath="id"
Lieferant表只有id和name两个字段,默认情况下SelectedValue可能直接指向了id;但Artikel表字段多,用ItemTemplate自定义行后,ListBox不知道该把哪个字段作为SelectedValue的返回值,这时候lbArtikel.SelectedValue返回的可能是整个Artikel实体对象,而不是你需要的id数字。

你可以检查Artikel窗体的ListBox XAML,补上这个配置:

<ListBox x:Name="lbArtikel" SelectedValuePath="id">
    <!-- 你的ItemTemplate内容 -->
</ListBox>

如果没加这个,后续Int32.Parse(lbArtikel.SelectedValue.ToString())肯定会报错——因为你在把一个对象的ToString结果(比如YourNamespace.Artikel)转成整数,这必然抛出格式异常,也就是你看到的警告。

2. 统一SQL参数的占位符写法

你的SQL语句用了?作为占位符,但添加参数时用的是@id——虽然部分ODBC驱动兼容这种混合写法,但MySQL的ODBC驱动对占位符的匹配要求其实很严格,建议统一写法:
要么用匿名占位符:

DELETE FROM artikel WHERE id=?

然后直接按顺序加参数(不用指定名称):

odbcCmd.Parameters.AddWithValue("", Int32.Parse(lbArtikel.SelectedValue.ToString()));

要么用命名占位符,SQL改成:

DELETE FROM artikel WHERE id=@id

然后参数对应@id,这样逻辑更清晰,也避免驱动识别出错。

3. 让异常信息帮你精准定位问题

你现在的catch块只显示了异常类型和消息,建议把堆栈信息也加上,这样能直接看到哪行代码出的问题:

catch (Exception ex) {
    MessageBox.Show($"{ex.GetType()}\n{ex.Message}\n{ex.StackTrace}", "Datenbankfehler");
}

比如如果是Int32.Parse报错,那就是SelectedValue的绑定问题;如果是ExecuteNonQuery报错,那就是SQL或者数据库权限的问题,一目了然。

4. 优化数据库资源的释放逻辑

你的finally块里直接调用odbcCmd.Parameters.Clear(),但如果try块里的代码还没走到创建odbcCmd的步骤(比如用户点了No取消删除),就会触发空引用异常。建议加上空判断,同时最好释放命令对象:

finally {
    odbcCon.Close();
    ArtikelShow();
    if(odbcCmd != null) {
        odbcCmd.Parameters.Clear();
        odbcCmd.Dispose(); // 释放命令资源
    }
}

更规范的写法是用using语句自动管理资源,不用手动关闭:

private void BtnDelete_Click(object sender, RoutedEventArgs e) { 
    if (lbArtikel.SelectedValue == null) { 
        MessageBox.Show("Keinen Eintrag zum Löschen ausgewählt"); 
        return;
    } 

    MessageBoxResult messageBoxResult = MessageBox.Show(
        "Wollen Sie wirklich den Artikel aus der Datenbank löschen?", 
        "Bitte bestätigen Sie den Löschvorgang", 
        MessageBoxButton.YesNo
    );
    if (messageBoxResult != MessageBoxResult.Yes) return;

    try { 
        string sqlDelete = "DELETE FROM artikel WHERE id=@id";
        using(OdbcConnection conn = new OdbcConnection(你的连接字符串)) {
            conn.Open();
            using(OdbcCommand cmd = new OdbcCommand(sqlDelete, conn)) {
                cmd.Parameters.AddWithValue("@id", Convert.ToInt32(lbArtikel.SelectedValue));
                cmd.ExecuteNonQuery();
            }
        }
    } catch (Exception ex) { 
        MessageBox.Show($"{ex.GetType()}\n{ex.Message}\n{ex.StackTrace}", "Datenbankfehler"); 
    } finally { 
        ArtikelShow(); 
    } 
}

using块会自动释放连接和命令对象,避免资源泄漏,代码也更简洁。


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

火山引擎 最新活动