如何将MySQL存储的RTF富文本正确加载到WPF RichTextBox控件中
问题根源
- SQL字符串拼接导致RTF内容损坏:RTF格式字符串中本身包含单引号
'字符,直接拼接进SQL语句会提前闭合字段的引号边界,导致最终存入数据库的RTF内容被截断、残缺,读取时无法被正常解析。同时该写法存在严重的SQL注入风险。
- SQL字符串拼接导致RTF内容损坏:RTF格式字符串中本身包含单引号
- 编码选择错误:使用7位ASCII编码转换RTF字节流,若RTF包含中文、特殊符号等超出ASCII范围的字符,会被直接替换为乱码,破坏RTF结构完整性。
- 加载逻辑缺陷:清空RichTextBox内容后,直接基于空文档的首尾位置创建TextRange,加载时无法正确插入RTF内容。
- 存储逻辑不合理:仅当
inpSupplierCode.Text不为空时才读取富文本内容,否则直接将Memo置空,不符合业务逻辑预期。
- 存储逻辑不合理:仅当
修复方案
1. 优先修改SQL为参数化查询(最核心修复)
无论你的Database封装类如何实现,必须停止直接拼接用户输入内容到SQL语句,改为参数传递,避免RTF中的特殊字符破坏SQL结构。示例修改如下(若你的Database类暂不支持参数,需自行扩展对应能力):
private void ToolbarButtonSave(object sender, RoutedEventArgs e) { string ContentSupplierMemo = ""; // 单独判断富文本内容,不要和SupplierCode绑定 TextRange tr = new(inpSupplierMemo.Document.ContentStart, inpSupplierMemo.Document.ContentEnd); if (!tr.IsEmpty) { using (MemoryStream ms = new()) { tr.Save(ms, DataFormats.Rtf); // 替换ASCII为UTF8编码,避免字符损坏 ContentSupplierMemo = Encoding.UTF8.GetString(ms.ToArray()); } } Database dbConnection = new Database { TableName = DatabaseTable }; dbConnection.Connect(); // 使用参数化SQL,不要拼接值 dbConnection.SqlCommandString = @"UPDATE " + DatabaseTable + @" SET supplier_Code = @supplier_Code, supplier_Name = @supplier_Name, supplier_Address1 = @supplier_Address1, supplier_Address2 = @supplier_Address2, supplier_Zip = @supplier_Zip, supplier_City = @supplier_City, supplier_Url = @supplier_Url, supplier_Memo = @supplier_Memo WHERE supplier_Id = @supplier_Id"; // 示例为常见的参数添加方式,可根据你的Database类实现调整 dbConnection.AddParameter("@supplier_Code", inpSupplierCode.Text); dbConnection.AddParameter("@supplier_Name", inpSupplierName.Text); dbConnection.AddParameter("@supplier_Address1", inpSupplierAddress1.Text); dbConnection.AddParameter("@supplier_Address2", inpSupplierAddress2.Text); dbConnection.AddParameter("@supplier_Zip", inpSupplierZip.Text); dbConnection.AddParameter("@supplier_City", inpSupplierCity.Text); dbConnection.AddParameter("@supplier_Url", inpSupplierUrl.Text); dbConnection.AddParameter("@supplier_Memo", ContentSupplierMemo); dbConnection.AddParameter("@supplier_Id", int.Parse(valueSupplierId.Text)); _ = dbConnection.UpdateMySqlDataRecord(); DataTable dtSupplierCodes = dbConnection.LoadMySqlData(); SupplierCode_DataGrid.DataContext = dtSupplierCodes; SupplierCode_DataGrid.SelectedIndex = int.Parse(valueSupplierId.Text) - 1; SupplierCode_DataGrid.Focus(); }
2. 修改富文本加载逻辑
调整加载时的文档处理逻辑,确保RTF能正确写入:
private void SupplierCode_DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { DataGrid dataGrid = (DataGrid)sender; if (dataGrid.SelectedItem is not DataRowView Row_Selected) { return; } valueSupplierId.Text = Row_Selected["supplier_Id"].ToString(); inpSupplierCode.Text = Row_Selected["supplier_Code"].ToString(); inpSupplierName.Text = Row_Selected["supplier_Name"].ToString(); inpSupplierAddress1.Text = Row_Selected["supplier_Address1"].ToString(); inpSupplierAddress2.Text = Row_Selected["supplier_Address2"].ToString(); inpSupplierZip.Text = Row_Selected["supplier_Zip"].ToString(); inpSupplierCity.Text = Row_Selected["supplier_City"].ToString(); inpSupplierUrl.Text = Row_Selected["supplier_Url"].ToString(); string ContentSupplierMemo = Row_Selected["supplier_Memo"].ToString(); inpSupplierMemo.Document.Blocks.Clear(); if (!string.IsNullOrEmpty(ContentSupplierMemo)) { // 和存储时对应使用UTF8编码 byte[] byteArray = Encoding.UTF8.GetBytes(ContentSupplierMemo); using (MemoryStream ms = new(byteArray)) { // 直接加载到新的FlowDocument再赋值,避免空范围问题 FlowDocument doc = new FlowDocument(); TextRange tr = new TextRange(doc.ContentStart, doc.ContentEnd); tr.Load(ms, DataFormats.Rtf); inpSupplierMemo.Document = doc; } } }
3. 可选优化
如果你的业务场景中富文本包含大量特殊格式,可将MySQL中存储字段从LONGTEXT改为BLOB类型,直接存储RTF的字节流,跳过字符串编码转换环节,彻底避免编码导致的内容损坏问题。
内容的提问来源于stack exchange,提问作者Herbert Nijkamp
相关产品推荐
相关产品推荐

