using System; using System.Collections.Generic; using System.Windows.Forms; namespace 成套报价软件 { /// /// 修改项目 的交互逻辑(事件处理)。 /// UI 布局定义见 修改项目.ui.cs。 /// 本窗体作为 MainForm 的对话框使用,故不含独立的 Main 入口点。 /// public partial class 修改项目 : Form { /// 项目数据库文件绝对路径(与 MainForm 保持一致)。 private readonly string _dbPath; /// 项目数据表名。 private readonly string _tableName; /// 当前要修改的项目编号(主键)。 private readonly string _projectId; /// /// 默认构造函数(无参保留,以便独立测试时仍可创建)。 /// 不做任何自动填充。 /// public 修改项目() { InitializeComponent(); InitPriceFormatCombos(); } /// /// 带数据库路径与现有项目数据的构造函数(主窗口调用此版本)。 /// 传入后对话框在 Load 时会把现有字段值填到各输入框里。 /// /// SQLite 数据库绝对路径。 /// 项目数据表名。 /// 要修改的项目编号(用于 WHERE 条件)。 /// 现有字段值(键=列名,值=字符串);为空则从数据库读取。 public 修改项目(string dbPath, string tableName, string projectId, Dictionary existing) { InitializeComponent(); InitPriceFormatCombos(); _dbPath = dbPath; _tableName = tableName; _projectId = projectId; _existingValues = existing; // 加载完成后(已显示)填充已有字段。 this.Load += 修改项目_Load; } /// /// 预置“单台价格/项目总价/单台取整/项目取整”4 个下拉框的“候选选项列表”。 /// 注意:只填充 Items,不改动 SelectedIndex/Text —— 默认值由设计器 XML 决定, /// 加载已有项目时由 FillFields 根据数据库内容覆盖。 /// /// 控件布局对应(UI 里 label 文字决定语义): /// 单台价格行 → cmb单台价格(单台层小数位) /// 项目总价行 → cmb项目总价(项目层小数位) /// 单台取整行 → comboBox1 (单台层取整方式) /// 项目取整行 → comboBox2 (项目层取整方式) /// private void InitPriceFormatCombos() { // 小数位选项:cmb单台价格(单台层) + cmb项目总价(项目层) this.cmb单台价格.Items.Clear(); this.cmb单台价格.Items.AddRange(价格格式化.小数位选项); this.cmb项目总价.Items.Clear(); this.cmb项目总价.Items.AddRange(价格格式化.小数位选项); // 取整方式选项:comboBox1(单台层) + comboBox2(项目层) this.comboBox1.Items.Clear(); this.comboBox1.Items.AddRange(价格格式化.取整方式选项); this.comboBox2.Items.Clear(); this.comboBox2.Items.AddRange(价格格式化.取整方式选项); } private readonly Dictionary _existingValues; /// 对话框首次加载:把已有项目数据填入各输入框。 private void 修改项目_Load(object sender, EventArgs e) { // 若未传入 existing,则按 projectId 从数据库读取 Dictionary data = _existingValues; if (data == null || data.Count == 0) { data = LoadProjectFromDatabase(); } FillFields(data); // 项目编号为主键,不允许修改 this.txt项目编号.ReadOnly = true; this.txt项目编号.TabStop = false; this.txt项目编号.BackColor = System.Drawing.SystemColors.Control; } /// /// 从数据库读取当前 projectId 的项目记录(单行)。 /// 找不到则返回空字典。 /// private Dictionary LoadProjectFromDatabase() { var dict = new Dictionary(); if (string.IsNullOrEmpty(_dbPath) || string.IsNullOrEmpty(_tableName) || string.IsNullOrEmpty(_projectId) || !System.IO.File.Exists(_dbPath)) { return dict; } try { string connStr = "Data Source=" + _dbPath + ";Version=3;"; using (var conn = new System.Data.SQLite.SQLiteConnection(connStr)) { conn.Open(); string sql = "SELECT * FROM " + _tableName + " WHERE 项目编号 = @id LIMIT 1;"; using (var cmd = new System.Data.SQLite.SQLiteCommand(sql, conn)) { cmd.Parameters.AddWithValue("@id", _projectId); using (var reader = cmd.ExecuteReader()) { if (reader.Read()) { for (int i = 0; i < reader.FieldCount; i++) { string col = reader.GetName(i); object v = reader.IsDBNull(i) ? "" : reader.GetValue(i); dict[col] = v == null ? "" : v.ToString(); } } } } } } catch { // 读取失败不阻断 UI,只是字段为空 } return dict; } /// 把字段字典按列名填到对应的输入框。 private void FillFields(Dictionary data) { if (data == null || data.Count == 0) { return; } this.txt项目编号.Text = GetOrNull(data, "项目编号"); this.txt项目日期.Text = GetOrNull(data, "项目日期"); this.txt项目名称.Text = GetOrNull(data, "项目名称"); this.txt客户名称.Text = GetOrNull(data, "客户名称"); this.txt客户地址.Text = GetOrNull(data, "客户地址"); this.txt联系人.Text = GetOrNull(data, "联系人"); this.txt联系电话.Text = GetOrNull(data, "联系电话"); this.txt成套厂名称.Text = GetOrNull(data, "成套厂名称"); this.txt成套厂地址.Text = GetOrNull(data, "成套厂地址"); this.txt成套厂联系人.Text = GetOrNull(data, "成套厂联系人"); this.txt成套厂联系电话.Text = GetOrNull(data, "成套厂联系电话"); this.txt备注.Text = GetOrNull(data, "备注"); // 下拉框:只有在数据库里有值时才覆盖,避免清空设计器默认项 string v; if ((v = GetOrNull(data, "报出方式")) != null) this.cmb报出方式.Text = v; if ((v = GetOrNull(data, "箱柜模板")) != null) this.cmb箱柜模板.Text = v; // 价格显示格式化(4 个字段):从「项目信息」表读出后回填到对应控件 // 控件对应:cmb单台价格=单台小数位 / cmb项目总价=项目小数位 / // comboBox1=单台取整方式 / comboBox2=项目取整方式 if ((v = GetOrNull(data, "单台小数位")) != null) { this.cmb单台价格.Text = v; // 单台层小数位 if (this.cmb单台价格.SelectedIndex < 0) this.cmb单台价格.Text = "保留整数"; } if ((v = GetOrNull(data, "项目小数位")) != null) { this.cmb项目总价.Text = v; // 项目层小数位 if (this.cmb项目总价.SelectedIndex < 0) this.cmb项目总价.Text = "保留整数"; } if ((v = GetOrNull(data, "单台取整方式")) != null) { this.comboBox1.Text = v; // 单台层取整方式 if (this.comboBox1.SelectedIndex < 0) this.comboBox1.Text = "四舍五入"; } if ((v = GetOrNull(data, "项目取整方式")) != null) { this.comboBox2.Text = v; // 项目层取整方式 if (this.comboBox2.SelectedIndex < 0) this.comboBox2.Text = "四舍五入"; } } private static string GetOrNull(Dictionary dict, string key) { string v; return dict.TryGetValue(key, out v) ? v : null; } /// /// 收集对话框中已填写的字段,以"字段名"为键返回。 /// 返回的字典包含所有可能存在的字段(含空值,供 UPDATE 用)。 /// 调用方按列名匹配。 /// public Dictionary GetInputValues() { var values = new Dictionary(); // 以下字段会进入数据库 UPDATE;字段名与MainForm advancedDataGridView6 列名一致。 values["项目名称"] = Safe(this.txt项目名称.Text); values["客户名称"] = Safe(this.txt客户名称.Text); values["客户地址"] = Safe(this.txt客户地址.Text); values["联系人"] = Safe(this.txt联系人.Text); values["联系电话"] = Safe(this.txt联系电话.Text); values["项目日期"] = Safe(this.txt项目日期.Text); values["备注"] = Safe(this.txt备注.Text); // 成套厂信息(4 个字段):新建项目时从企业信息带入,这里随项目一起 UPDATE 回写 values["成套厂名称"] = Safe(this.txt成套厂名称.Text); values["成套厂地址"] = Safe(this.txt成套厂地址.Text); values["成套厂联系人"] = Safe(this.txt成套厂联系人.Text); values["成套厂联系电话"] = Safe(this.txt成套厂联系电话.Text); // 价格显示格式化(4 个字段):控制报价页价格单元格的“小数位 + 取整方式” // 控件对应:cmb单台价格=单台小数位 / cmb项目总价=项目小数位 / // comboBox1=单台取整方式 / comboBox2=项目取整方式 values["单台小数位"] = (this.cmb单台价格.SelectedItem ?? this.cmb单台价格.Text ?? "保留整数").ToString(); values["项目小数位"] = (this.cmb项目总价.SelectedItem ?? this.cmb项目总价.Text ?? "保留整数").ToString(); values["单台取整方式"] = (this.comboBox1.SelectedItem ?? this.comboBox1.Text ?? "四舍五入").ToString(); values["项目取整方式"] = (this.comboBox2.SelectedItem ?? this.comboBox2.Text ?? "四舍五入").ToString(); return values; } private static string Safe(string s) { return s == null ? "" : s.Trim(); } // 提示:在设计器的属性窗口(事件页)双击事件名, // 会自动在此生成事件处理方法骨架。 } }