已解决如何从(MySQL)表中检索 RichText 内容到 WPF RichTextBox
Posted
技术标签:
【中文标题】已解决如何从(MySQL)表中检索 RichText 内容到 WPF RichTextBox【英文标题】:SOLVED How to retrieve RichText content From (MySQL) table to a WPF RichTextBox 【发布时间】:2021-09-30 14:04:04 【问题描述】:谢谢你们,我可以使用 user9938 和 Bradley Grainger 给出的答案,不仅它有效,我也理解它现在为什么有效。我能得到最好的帮助。
现在我将处理有关在我的数据库表中的字段命名和在代码中参数化 SQL 数据的并行给出的建议。
我有一个应用程序,我必须在我的 WPF 页面中存储(和检索)供应商数据,其中一个字段是 RichTextBox
在我的 Xaml 页面上,我定义了这样的富文本块
<TabItem Header="Memo">
<Grid Background="#FFE5E5E5">
<TextBlock Text="Comments" HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="10,10" FontWeight="Bold" Foreground="DarkRed"/>
<RichTextBox x:Name="inpSupplierMemo" HorizontalAlignment="Center"
VerticalAlignment="Top" Margin="10,70,10,0" Height="182" Width="Auto">
<FlowDocument>
<Paragraph>
<Run Text=""/>
</Paragraph>
</FlowDocument>
</RichTextBox>
</Grid>
</TabItem>
在我的 mysql 数据库表中,我将字段定义为 LONGTEXT
我的 C# 代码将富文本数据存储到字段中:
private void ToolbarButtonSave(object sender, RoutedEventArgs e)
string ContentSupplierMemo;
if (inpSupplierCode.Text != "")
TextRange tr = new(inpSupplierMemo.Document.ContentStart,
inpSupplierMemo.Document.ContentEnd);
using (MemoryStream ms = new())
tr.Save(ms, DataFormats.Rtf);
ContentSupplierMemo = Encoding.ASCII.GetString(ms.ToArray());
else ContentSupplierMemo = "";
Database dbConnection = new Database
TableName = DatabaseTable
;
dbConnection.Connect();
dbConnection.SqlCommand = "UPDATE ";
dbConnection.SqlCommandString = " SET " +
"supplier_Code = '" + inpSupplierCode.Text + "', " +
"supplier_Name = '" + inpSupplierName.Text + "', " +
"supplier_Address1 = '" + inpSupplierAddress1.Text + "', " +
"supplier_Address2 = '" + inpSupplierAddress2.Text + "', " +
"supplier_Zip = '" + inpSupplierZip.Text + "', " +
"supplier_City = '" + inpSupplierCity.Text + "', " +
"supplier_Url = '" + inpSupplierUrl.Text + "', " +
"supplier_Memo = '" + ContentSupplierMemo + "', " +
"supplier_Id = " + valueSupplierId.Text + ";";
dbConnection.TableName = DatabaseTable;
_ = dbConnection.UpdateMySqlDataRecord();
DataTable dtSupplierCodes = dbConnection.LoadMySqlData();
// Load the data from the database into the datagrid
SupplierCode_DataGrid.DataContext = dtSupplierCodes;
// Make sure the eddited row in the datagrid is selected
SupplierCode_DataGrid.SelectedIndex = int.Parse(valueSupplierId.Text) - 1;
SupplierCode_DataGrid.Focus();
到目前为止显示 RichTextBox 并保存数据。 如果我运行应用程序,我可以输入文本并保存(屏幕截图中未显示保存按钮)
富文本框的内容存储在数据库中
及详细内容
到目前为止一切顺利 但是当我从数据库中检索内容时,我无法再显示原始内容了。
我用于数据检索的 C# 代码:
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();
inpSupplierMemo.Document.Blocks.Clear();
// Read formatted ritch text from table and store in field
string ContentSupplierMemo = Row_Selected["supplier_Memo"].ToString();
if (ContentSupplierMemo != "")
byte[] byteArray = Encoding.ASCII.GetBytes(ContentSupplierMemo);
using (MemoryStream ms = new(byteArray))
TextRange tr = new(inpSupplierMemo.Document.ContentStart, inpSupplierMemo.Document.ContentEnd);
tr.Load(ms, DataFormats.Rtf);
而这段代码的结果是:
但我期待
我哪里出错了,谁能帮帮我。
我用谷歌搜索了三天,只看到或多或少相同的解决方案,尝试了不同的解决方案,但有了这个解决方案,我最接近我的目标,但还没有。
问候, 赫伯特
【问题讨论】:
确保使用参数化查询来防止 SQL 注入。 您能否检查“valueSupplierId”的值,如果它实际上是数据网格中的第 n 行(没有间隙,没有重新排序,...) @user9938,我想稍后在代码运行正常时进行参数化,仍在学习过程中,所以采取小步骤 我在下面添加了两个帖子——一个使用longtext
,另一个使用longbinary
。因为,两者之间存在许多差异——为了避免混淆——我在每篇文章中添加了完整的代码。在longtext
版本中,您会注意到我在将字符串转换为字节[] 时使用了UTF8
而不是ASCII
。重点关注的两个方法是“MainWindow.xaml.cs”中的GetMemo()
和GetRichTextFromFlowDocument()
【参考方案1】:
下面是一个演示项目,展示了如何将来自 TextBlock 的数据存储到数据库中。它还展示了如何从数据库中检索数据并将其显示在 TextBlock 中。
以下代码已经过测试。 longtext
用于supplier_Memo
。或者,可以使用longblob
(或mediumblob
,如果它满足您的需要)。由于longblob
是二进制数据,因此需要修改下面的代码以将数据作为byte[]
而不是string
传递。
使用参数来避免 SQL 注入也很重要。
新建WPF App (.NET Framework)
项目(名称:DatabaseMySqlHN)
VS 2019:
MainWindow.xaml
<Window x:Class="DatabaseMySqlHN.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DatabaseMySqlHN"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="25" />
<RowDefinition Height="150" />
<RowDefinition Height="25" />
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" x:Name="btnCreateTbl" Click="btnCreateTbl_Click">Create Table</Button>
<Button Grid.Column="2" x:Name="btnInsertTestData" Click="btnInsertTestData_Click">Insert Test Data</Button>
<Button Grid.Column="4" x:Name="btnGetData" Click="btnGetData_Click">Get Data</Button>
<Button Grid.Column="6" x:Name="btnSaveUpdate" Click="btnSaveUpdate_Click">Save/Update</Button>
</Grid>
<DataGrid Grid.Row="2" x:Name="SupplierCode_DataGrid" ItemsSource="Binding" SelectionChanged="SupplierCode_DataGrid_SelectionChanged"></DataGrid>
<TabControl Grid.Row="4" x:Name="tabControl1">
<TabItem Header="Memo">
<Grid Background="#FFE5E5E5">
<TextBlock Text="Comments" HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="10,10" FontWeight="Bold" Foreground="DarkRed"/>
<RichTextBox x:Name="inpSupplierMemo" HorizontalAlignment="Center"
VerticalAlignment="Top" Margin="10,70,10,0" Height="182" Width="Auto">
<FlowDocument Name="inpSupplierMemoFD">
<Paragraph>
<Run Text=""/>
</Paragraph>
</FlowDocument>
</RichTextBox>
</Grid>
</TabItem>
</TabControl>
<TextBox Grid.Row="5" Name="textBoxStatus" IsReadOnly="True" Text="" Background="LightGray"></TextBox>
</Grid>
</Window>
数据库表:供应商
注意:在下面的代码中,我尝试维护 OP 中提供的数据库列名。但是,表名实际上不应该是列名的一部分。
不要将列命名为supplier_Code
,而是将列命名为Code
。
可能需要根据您的要求添加/修改列。
CREATE TABLE Supplier (supplier_Id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
supplier_Code varchar(4),
supplier_Name varchar(80),
supplier_Address1 varchar(80),
supplier_Address2 varchar(80),
supplier_Zip varchar(80),
supplier_City varchar(80),
supplier_Url varchar(80),
supplier_MailSales varchar(80),
supplier_MailSupport varchar(80),
supplier_Memo longtext,
currency_Id int,
currency_Code varchar(4));
创建一个类(名称:HelperMySql.cs)
HelperMySql.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql.Data;
using MySql.Data.MySqlClient;
using System.Data;
using System.Diagnostics;
namespace DatabaseMySqlHN
public class HelperMySQL
public string ConnectionStr get; set; = string.Empty;
public HelperMySQL(string serverName, string databaseName, string username, string userPwd)
ConnectionStr = String.Format("Server=0;Database=1;Uid=2;Pwd=3;", serverName, databaseName, username, userPwd);
public HelperMySQL(string serverName, int portNumber, string databaseName, string username, string userPwd)
ConnectionStr = String.Format("Server=0;Port=1;Database=2;Uid=3;Pwd=4;", serverName, portNumber, databaseName, username, userPwd);
public string CreateTableSupplier()
string msg = string.Empty;
try
//for mySQL, use backticks if tablename has space in it
//total max size for all columns is 65535 - excluding TEXT and BLOB
string sqlText = @"CREATE TABLE Supplier (supplier_Id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
supplier_Code varchar(4),
supplier_Name varchar(80),
supplier_Address1 varchar(80),
supplier_Address2 varchar(80),
supplier_Zip varchar(80),
supplier_City varchar(80),
supplier_Url varchar(80),
supplier_MailSales varchar(80),
supplier_MailSupport varchar(80),
supplier_Memo longtext,
currency_Id int,
currency_Code varchar(4));";
ExecuteNonQuery(sqlText);
Debug.WriteLine("Info: Table created (Supplier)");
msg = "Status: Table created (Supplier).";
catch (MySqlException ex)
msg = "Error: (CreateTableSupplier - MySqlException) - " + ex.Message;
Debug.WriteLine(msg);
//throw ex;
catch (Exception ex)
msg = "Error: (CreateTableSupplier) - " + ex.Message;
Debug.WriteLine(msg);
//throw ex;
return msg;
public void ExecuteNonQuery(string sqlText)
using (MySqlConnection con = new MySqlConnection(ConnectionStr))
//open
con.Open();
using (MySqlCommand cmd = new MySqlCommand(sqlText, con))
//execute
cmd.ExecuteNonQuery();
public int ExecuteNonQueryTblSupplier(string sqlText, string supplierCode, string supplierName, string supplierAddress1, string supplierAddress2, string supplierZip, string supplierCity, string supplierUrl, string supplierMemo, int supplierId = 0)
int rowsAffected = 0;
using (MySqlConnection con = new MySqlConnection(ConnectionStr))
//open
con.Open();
using (MySqlCommand cmd = new MySqlCommand(sqlText, con))
//set values - if they exist
//if a value is null, one must use DBNull.Value
//if the value is DBNull.Value, and the table column doesn't allow nulls, this will cause an error
//add parameters setting string values to DBNull.Value
cmd.Parameters.Add("@supplierId", MySqlDbType.Int32).Value = supplierId;
cmd.Parameters.Add("@supplierCode", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierName", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierAddress1", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierAddress2", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierZip", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierCity", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierUrl", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierMemo", MySqlDbType.LongText).Value = DBNull.Value;
//set values
if (!String.IsNullOrEmpty(supplierCode))
cmd.Parameters["@supplierCode"].Value = supplierCode;
if (!String.IsNullOrEmpty(supplierName))
cmd.Parameters["@supplierName"].Value = supplierName;
if (!String.IsNullOrEmpty(supplierAddress1))
cmd.Parameters["@supplierAddress1"].Value = supplierAddress1;
if (!String.IsNullOrEmpty(supplierAddress2))
cmd.Parameters["@supplierAddress2"].Value = supplierAddress2;
if (!String.IsNullOrEmpty(supplierZip))
cmd.Parameters["@supplierZip"].Value = supplierZip;
if (!String.IsNullOrEmpty(supplierCity))
cmd.Parameters["@supplierCity"].Value = supplierCity;
if (!String.IsNullOrEmpty(supplierUrl))
cmd.Parameters["@supplierUrl"].Value = supplierUrl;
if (supplierMemo != null && supplierMemo.Length > 0)
cmd.Parameters["@supplierMemo"].Value = supplierMemo;
//execute; returns the number of rows affected
rowsAffected = cmd.ExecuteNonQuery();
return rowsAffected;
public DataTable GetDataTblSupplier(int supplierId = 0)
DataTable dt = new DataTable();
string sqlText = string.Empty;
if (supplierId > 0)
sqlText = "SELECT * from Supplier where supplier_Id = @supplierId";
else
sqlText = "SELECT * from Supplier";
using (MySqlConnection con = new MySqlConnection(ConnectionStr))
//open
con.Open();
using (MySqlCommand cmd = new MySqlCommand(sqlText, con))
//add parameter
cmd.Parameters.Add("@supplierId", MySqlDbType.Int32).Value = supplierId;
using (MySqlDataAdapter da = new MySqlDataAdapter(cmd))
//use DataAdapter to fill DataTable
da.Fill(dt);
return dt;
public string InsertTblSupplier(string supplierCode, string supplierName, string supplierAddress1, string supplierAddress2, string supplierZip, string supplierCity, string supplierUrl, string supplierMemo)
string result = string.Empty;
string sqlText = "INSERT INTO Supplier (supplier_Code, supplier_Name, supplier_Address1, supplier_Address2, supplier_Zip, supplier_City, supplier_Url, supplier_Memo) VALUES (@supplierCode, @supplierName, @supplierAddress1, @supplierAddress2, @supplierZip, @supplierCity, @supplierUrl, @supplierMemo);";
try
int rowsAffected = ExecuteNonQueryTblSupplier(sqlText, supplierCode, supplierName, supplierAddress1, supplierAddress2, supplierZip, supplierCity, supplierUrl, supplierMemo);
if (rowsAffected > 0)
result = String.Format("Row added.");
else
result = "Row not added.";
catch (MySqlException ex)
Debug.WriteLine("Error (UpdateTblSupplier - MySqlException): " + ex.Message);
throw ex;
catch (Exception ex)
Debug.WriteLine("Error (UpdateTblSupplier): " + ex.Message);
throw ex;
return result;
public string UpdateTblSupplier(int supplierId, string supplierCode, string supplierName, string supplierAddress1, string supplierAddress2, string supplierZip, string supplierCity, string supplierUrl, string supplierMemo)
string result = string.Empty;
string sqlText = "UPDATE Supplier SET supplier_Code = @supplierCode, supplier_name = @supplierName, supplier_Address1 = @supplierAddress1, supplier_Address2 = @supplierAddress2, supplier_Zip = @supplierZip, supplier_City = @supplierCity, supplier_Url = @supplierUrl, supplier_Memo = @supplierMemo WHERE supplier_Id = @supplierId;";
try
int rowsAffected = ExecuteNonQueryTblSupplier(sqlText, supplierCode, supplierName, supplierAddress1, supplierAddress2, supplierZip, supplierCity, supplierUrl, supplierMemo, supplierId);
if (rowsAffected > 0)
result = "Updated successfully";
else
result = "No rows were updated.";
catch (MySqlException ex)
Debug.WriteLine("Error (UpdateTblSupplier - MySqlException): " + ex.Message);
throw ex;
catch (Exception ex)
Debug.WriteLine("Error (UpdateTblSupplier): " + ex.Message);
throw ex;
return result;
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Data;
using System.IO;
namespace DatabaseMySqlHN
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
private HelperMySQL _helper = null;
private System.Data.DataTable _dt = null;
private int _currentDataGridIndex = 0;
private int _dbRowCount = 0;
public MainWindow()
InitializeComponent();
private void GetData()
InitializeHelper();
//get data from database
_dt = _helper.GetDataTblSupplier();
//populate data in DataGrid from DataTable
SupplierCode_DataGrid.DataContext = _dt;
//set value
_dbRowCount = _dt.Rows.Count;
//clear existing data
inpSupplierMemo.Document.Blocks.Clear();
private void GetMemo(int index)
string ContentSupplierMemo = string.Empty;
if (_dt != null && index >= 0 && index < _dt.Rows.Count)
//set value
DataRow row = _dt.Rows[index];
if (row["supplier_Memo"] != null && row["supplier_Memo"] != DBNull.Value)
//get value from DataTable
ContentSupplierMemo = row["supplier_Memo"].ToString();
if (!String.IsNullOrEmpty(ContentSupplierMemo))
//Debug.WriteLine("Length: " + ContentSupplierMemo.Length);
//clear existing data
inpSupplierMemo.Document.Blocks.Clear();
//convert to byte[]
byte[] dataArr = System.Text.Encoding.UTF8.GetBytes(ContentSupplierMemo);
using (MemoryStream ms = new MemoryStream(dataArr))
//inpSupplierMemo.Document = new FlowDocument();
//load data
TextRange flowDocRange = new TextRange(inpSupplierMemo.Document.ContentStart, inpSupplierMemo.Document.ContentEnd);
flowDocRange.Load(ms, DataFormats.Rtf);
private string GetRichTextFromFlowDocument(FlowDocument fDoc)
string result = string.Empty;
//convert to string
if (fDoc != null)
TextRange tr = new TextRange(fDoc.ContentStart, fDoc.ContentEnd);
using (MemoryStream ms = new MemoryStream())
tr.Save(ms, DataFormats.Rtf);
result = System.Text.Encoding.UTF8.GetString(ms.ToArray());
return result;
private void InitializeHelper()
if (_helper == null)
//servername, databaseName, userName, userPassword
_helper = new HelperMySQL("localhost", "HN", "testUser", "removed");
private void InsertRow(int dgIndex)
//since the DataGrid DataContext is set to the DataTable,
//the DataTable is updated when data is modified in the DataGrid
//get last row
DataRow row = _dt.Rows[_dt.Rows.Count - 1];
//get data from DataTable
string supplierCode = row["supplier_Code"].ToString();
string supplierName = row["supplier_Name"].ToString();
string supplierAddress1 = row["supplier_Address1"].ToString();
string supplierAddress2 = row["supplier_Address2"].ToString();
string supplier_Zip = row["supplier_Zip"].ToString();
string supplier_City = row["supplier_City"].ToString();
string supplier_Url = row["supplier_Url"].ToString();
//convert RTF to string
string memo = GetRichTextFromFlowDocument(inpSupplierMemo.Document);
InitializeHelper();
string result = string.Empty;
result = _helper.InsertTblSupplier(supplierCode, supplierName, supplierAddress1, supplierAddress2, supplier_Zip, supplier_City, supplier_Url, memo);
UpdateStatus(result);
private void UpdateRow(int dgIndex)
//when DataGrid SelectionChanged occurs, the value of '_currentDataGridIndex' is set
//to DataGrid SelectedIndex
//get data from DataTable
DataRow row = _dt.Rows[_currentDataGridIndex];
int supplierId = (int)row["supplier_Id"];
string supplierCode = row["supplier_Code"].ToString();
string supplierName = row["supplier_Name"].ToString();
string supplierAddress1 = row["supplier_Address1"].ToString();
string supplierAddress2 = row["supplier_Address2"].ToString();
string supplier_Zip = row["supplier_Zip"].ToString();
string supplier_City = row["supplier_City"].ToString();
string supplier_Url = row["supplier_Url"].ToString();
//convert RTF to string
string memo = GetRichTextFromFlowDocument(inpSupplierMemo.Document);
InitializeHelper();
string result = string.Empty;
result = _helper.UpdateTblSupplier(supplierId, supplierCode, supplierName, supplierAddress1, supplierAddress2, supplier_Zip, supplier_City, supplier_Url, memo);
UpdateStatus(result);
private void UpdateStatus(string msg)
if (!String.IsNullOrEmpty(msg))
if (!msg.StartsWith("Error") && !msg.StartsWith("Status"))
textBoxStatus.Text = String.Format("Status: 0 (1)", msg, DateTime.Now.ToString("HH:mm:ss"));
Debug.WriteLine(String.Format("0 - Status: 1", DateTime.Now.ToString("HH:mm:ss"), msg));
else
textBoxStatus.Text = String.Format("0 (1)", msg, DateTime.Now.ToString("HH:mm:ss"));
Debug.WriteLine(String.Format("0 - 1", DateTime.Now.ToString("HH:mm:ss"), msg));
private void btnCreateTbl_Click(object sender, RoutedEventArgs e)
InitializeHelper();
//create table
string result = _helper.CreateTableSupplier();
UpdateStatus(result);
private void btnGetData_Click(object sender, RoutedEventArgs e)
GetData();
//update status
string msg = "Status: '" + _dt.Rows.Count + "' rows retrieved.";
UpdateStatus(msg);
private void SupplierCode_DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
DataGrid dg = (DataGrid)sender;
//set value
_currentDataGridIndex = dg.SelectedIndex;
GetMemo(dg.SelectedIndex);
private void btnSaveUpdate_Click(object sender, RoutedEventArgs e)
int rowIndex = _currentDataGridIndex;
if (_dt.Rows.Count > _dbRowCount)
InsertRow(SupplierCode_DataGrid.SelectedIndex);
else
UpdateRow(SupplierCode_DataGrid.SelectedIndex);
GetData();
// Make sure the eddited row in the datagrid is selected
SupplierCode_DataGrid.SelectedIndex = rowIndex;
SupplierCode_DataGrid.Focus();
private void btnInsertTestData_Click(object sender, RoutedEventArgs e)
string result = string.Empty;
GetData();
//only insert test data if no rows exist
if (_dt.Rows.Count == 0)
string memo1 = @"\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033\fonttbl\f0\fnil\fcharset0 Calibri;
\*\generator Riched20 10.0.19041\viewkind4\uc1
\pard\sa200\sl276\slmult1\f0\fs22\lang9 Test Comments 1\par
";
string memo2 = @"\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033\fonttbl\f0\fnil\fcharset0 Calibri;
\*\generator Riched20 10.0.19041\viewkind4\uc1
\pard\sa200\sl276\slmult1\f0\fs22\lang9 Test Comments 2\par
";
InitializeHelper();
result = _helper.InsertTblSupplier("1", "Acme 123", "51 my street", null, "12345", "Some City", "https://www.myUrl1.com", memo1);
UpdateStatus(result);
result = _helper.InsertTblSupplier("2", "Acme 456", "52 my street", null, "12345", "Some City", "https://www.myUrl2.com", memo2);
UpdateStatus(result);
GetData();
else
UpdateStatus("Status: Data exists in table-test data not added.");
资源:
rtf to textblock FlowDocumentScrollViewer【讨论】:
【参考方案2】:下面是一个演示项目,展示了如何将来自 TextBlock 的数据存储到数据库中。它还展示了如何从数据库中检索数据并将其显示在 TextBlock 中。
以下代码已经过测试。 longblob
用于supplier_Memo
。或者,如果它满足您的需求,可以使用mediumblob
。
使用参数来避免 SQL 注入也很重要。
新建WPF App (.NET Framework)
项目(名称:DatabaseMySqlHN)
VS 2019:
MainWindow.xaml
<Window x:Class="DatabaseMySqlHN.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:DatabaseMySqlHN"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="25" />
<RowDefinition Height="150" />
<RowDefinition Height="25" />
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="10" />
<ColumnDefinition Width="100" />
<ColumnDefinition Width="10" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" x:Name="btnCreateTbl" Click="btnCreateTbl_Click">Create Table</Button>
<Button Grid.Column="2" x:Name="btnInsertTestData" Click="btnInsertTestData_Click">Insert Test Data</Button>
<Button Grid.Column="4" x:Name="btnGetData" Click="btnGetData_Click">Get Data</Button>
<Button Grid.Column="6" x:Name="btnSaveUpdate" Click="btnSaveUpdate_Click">Save/Update</Button>
</Grid>
<DataGrid Grid.Row="2" x:Name="SupplierCode_DataGrid" ItemsSource="Binding" SelectionChanged="SupplierCode_DataGrid_SelectionChanged"></DataGrid>
<TabControl Grid.Row="4" x:Name="tabControl1">
<TabItem Header="Memo">
<Grid Background="#FFE5E5E5">
<TextBlock Text="Comments" HorizontalAlignment="Left" VerticalAlignment="Top"
Margin="10,10" FontWeight="Bold" Foreground="DarkRed"/>
<RichTextBox x:Name="inpSupplierMemo" HorizontalAlignment="Center"
VerticalAlignment="Top" Margin="10,70,10,0" Height="182" Width="Auto">
<FlowDocument Name="inpSupplierMemoFD">
<Paragraph>
<Run Text=""/>
</Paragraph>
</FlowDocument>
</RichTextBox>
</Grid>
</TabItem>
</TabControl>
<TextBox Grid.Row="5" Name="textBoxStatus" IsReadOnly="True" Text="" Background="LightGray"></TextBox>
</Grid>
</Window>
数据库表:供应商
注意:在下面的代码中,我尝试维护 OP 中提供的数据库列名。但是,表名实际上不应该是列名的一部分。
不要将列命名为supplier_Code
,而是将列命名为Code
。
可能需要根据您的要求添加/修改列。
CREATE TABLE Supplier (supplier_Id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
supplier_Code varchar(4),
supplier_Name varchar(80),
supplier_Address1 varchar(80),
supplier_Address2 varchar(80),
supplier_Zip varchar(80),
supplier_City varchar(80),
supplier_Url varchar(80),
supplier_MailSales varchar(80),
supplier_MailSupport varchar(80),
supplier_Memo longblob,
currency_Id int,
currency_Code varchar(4));
创建一个类(名称:HelperMySql.cs)
HelperMySql.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MySql.Data;
using MySql.Data.MySqlClient;
using System.Data;
using System.Diagnostics;
namespace DatabaseMySqlHN
public class HelperMySQL
public string ConnectionStr get; set; = string.Empty;
public HelperMySQL(string serverName, string databaseName, string username, string userPwd)
ConnectionStr = String.Format("Server=0;Database=1;Uid=2;Pwd=3;", serverName, databaseName, username, userPwd);
public HelperMySQL(string serverName, int portNumber, string databaseName, string username, string userPwd)
ConnectionStr = String.Format("Server=0;Port=1;Database=2;Uid=3;Pwd=4;", serverName, portNumber, databaseName, username, userPwd);
public string CreateTableSupplier()
string msg = string.Empty;
try
//for mySQL, use backticks if tablename has space in it
//total max size for all columns is 65535 - excluding TEXT and BLOB
string sqlText = @"CREATE TABLE Supplier (supplier_Id int NOT NULL AUTO_INCREMENT PRIMARY KEY,
supplier_Code varchar(4),
supplier_Name varchar(80),
supplier_Address1 varchar(80),
supplier_Address2 varchar(80),
supplier_Zip varchar(80),
supplier_City varchar(80),
supplier_Url varchar(80),
supplier_MailSales varchar(80),
supplier_MailSupport varchar(80),
supplier_Memo longblob,
currency_Id int,
currency_Code varchar(4));";
ExecuteNonQuery(sqlText);
Debug.WriteLine("Info: Table created (Supplier)");
msg = "Status: Table created (Supplier).";
catch (MySqlException ex)
msg = "Error: (CreateTableSupplier - MySqlException) - " + ex.Message;
Debug.WriteLine(msg);
//throw ex;
catch (Exception ex)
msg = "Error: (CreateTableSupplier) - " + ex.Message;
Debug.WriteLine(msg);
//throw ex;
return msg;
public void ExecuteNonQuery(string sqlText)
using (MySqlConnection con = new MySqlConnection(ConnectionStr))
//open
con.Open();
using (MySqlCommand cmd = new MySqlCommand(sqlText, con))
//execute
cmd.ExecuteNonQuery();
public int ExecuteNonQueryTblSupplier(string sqlText, string supplierCode, string supplierName, string supplierAddress1, string supplierAddress2, string supplierZip, string supplierCity, string supplierUrl, byte[] supplierMemo, int supplierId = 0)
int rowsAffected = 0;
using (MySqlConnection con = new MySqlConnection(ConnectionStr))
//open
con.Open();
using (MySqlCommand cmd = new MySqlCommand(sqlText, con))
//set values - if they exist
//if a value is null, one must use DBNull.Value
//if the value is DBNull.Value, and the table column doesn't allow nulls, this will cause an error
//add parameters setting string values to DBNull.Value
cmd.Parameters.Add("@supplierId", MySqlDbType.Int32).Value = supplierId;
cmd.Parameters.Add("@supplierCode", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierName", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierAddress1", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierAddress2", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierZip", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierCity", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierUrl", MySqlDbType.VarChar).Value = DBNull.Value;
cmd.Parameters.Add("@supplierMemo", MySqlDbType.LongBlob).Value = DBNull.Value;
//set values
if (!String.IsNullOrEmpty(supplierCode))
cmd.Parameters["@supplierCode"].Value = supplierCode;
if (!String.IsNullOrEmpty(supplierName))
cmd.Parameters["@supplierName"].Value = supplierName;
if (!String.IsNullOrEmpty(supplierAddress1))
cmd.Parameters["@supplierAddress1"].Value = supplierAddress1;
if (!String.IsNullOrEmpty(supplierAddress2))
cmd.Parameters["@supplierAddress2"].Value = supplierAddress2;
if (!String.IsNullOrEmpty(supplierZip))
cmd.Parameters["@supplierZip"].Value = supplierZip;
if (!String.IsNullOrEmpty(supplierCity))
cmd.Parameters["@supplierCity"].Value = supplierCity;
if (!String.IsNullOrEmpty(supplierUrl))
cmd.Parameters["@supplierUrl"].Value = supplierUrl;
if (supplierMemo != null && supplierMemo.Length > 0)
cmd.Parameters["@supplierMemo"].Value = supplierMemo;
//execute; returns the number of rows affected
rowsAffected = cmd.ExecuteNonQuery();
return rowsAffected;
public DataTable GetDataTblSupplier(int supplierId = 0)
DataTable dt = new DataTable();
string sqlText = string.Empty;
if (supplierId > 0)
sqlText = "SELECT * from Supplier where supplier_Id = @supplierId";
else
sqlText = "SELECT * from Supplier";
using (MySqlConnection con = new MySqlConnection(ConnectionStr))
//open
con.Open();
using (MySqlCommand cmd = new MySqlCommand(sqlText, con))
//add parameter
cmd.Parameters.Add("@supplierId", MySqlDbType.Int32).Value = supplierId;
using (MySqlDataAdapter da = new MySqlDataAdapter(cmd))
//use DataAdapter to fill DataTable
da.Fill(dt);
return dt;
public string InsertTblSupplier(string supplierCode, string supplierName, string supplierAddress1, string supplierAddress2, string supplierZip, string supplierCity, string supplierUrl, byte[] supplierMemo)
string result = string.Empty;
string sqlText = "INSERT INTO Supplier (supplier_Code, supplier_Name, supplier_Address1, supplier_Address2, supplier_Zip, supplier_City, supplier_Url, supplier_Memo) VALUES (@supplierCode, @supplierName, @supplierAddress1, @supplierAddress2, @supplierZip, @supplierCity, @supplierUrl, @supplierMemo);";
try
int rowsAffected = ExecuteNonQueryTblSupplier(sqlText, supplierCode, supplierName, supplierAddress1, supplierAddress2, supplierZip, supplierCity, supplierUrl, supplierMemo);
if (rowsAffected > 0)
result = String.Format("Row added.");
else
result = "Row not added.";
catch (MySqlException ex)
Debug.WriteLine("Error (UpdateTblSupplier - MySqlException): " + ex.Message);
throw ex;
catch (Exception ex)
Debug.WriteLine("Error (UpdateTblSupplier): " + ex.Message);
throw ex;
return result;
public string UpdateTblSupplier(int supplierId, string supplierCode, string supplierName, string supplierAddress1, string supplierAddress2, string supplierZip, string supplierCity, string supplierUrl, byte[] supplierMemo)
string result = string.Empty;
string sqlText = "UPDATE Supplier SET supplier_Code = @supplierCode, supplier_name = @supplierName, supplier_Address1 = @supplierAddress1, supplier_Address2 = @supplierAddress2, supplier_Zip = @supplierZip, supplier_City = @supplierCity, supplier_Url = @supplierUrl, supplier_Memo = @supplierMemo WHERE supplier_Id = @supplierId;";
try
int rowsAffected = ExecuteNonQueryTblSupplier(sqlText, supplierCode, supplierName, supplierAddress1, supplierAddress2, supplierZip, supplierCity, supplierUrl, supplierMemo, supplierId);
if (rowsAffected > 0)
result = "Updated successfully";
else
result = "No rows were updated.";
catch (MySqlException ex)
Debug.WriteLine("Error (UpdateTblSupplier - MySqlException): " + ex.Message);
throw ex;
catch (Exception ex)
Debug.WriteLine("Error (UpdateTblSupplier): " + ex.Message);
throw ex;
return result;
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Diagnostics;
using System.Data;
using System.IO;
namespace DatabaseMySqlHN
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
private HelperMySQL _helper = null;
private System.Data.DataTable _dt = null;
private int _currentDataGridIndex = 0;
private int _dbRowCount = 0;
public MainWindow()
InitializeComponent();
private void GetData()
InitializeHelper();
//get data from database
_dt = _helper.GetDataTblSupplier();
//populate data in DataGrid from DataTable
SupplierCode_DataGrid.DataContext = _dt;
//set value
_dbRowCount = _dt.Rows.Count;
//clear existing data
inpSupplierMemo.Document.Blocks.Clear();
private void GetMemo(int index)
byte[] dataArr = null;
if (_dt != null && index >= 0 && index < _dt.Rows.Count)
//set value
DataRow row = _dt.Rows[index];
if (row["supplier_Memo"] != null && row["supplier_Memo"] != DBNull.Value)
//get value from DataTable
dataArr = (byte[])row["supplier_Memo"];
if (dataArr != null)
//Debug.WriteLine("Length: " + dataArr.Length);
//clear existing data
inpSupplierMemo.Document.Blocks.Clear();
using (MemoryStream ms = new MemoryStream(dataArr))
//inpSupplierMemo.Document = new FlowDocument();
//load data
TextRange flowDocRange = new TextRange(inpSupplierMemo.Document.ContentStart, inpSupplierMemo.Document.ContentEnd);
flowDocRange.Load(ms, DataFormats.Rtf);
private byte[] GetRichTextFromFlowDocument(FlowDocument fDoc)
byte[] result = null;
//convert to string
if (fDoc != null)
TextRange tr = new TextRange(fDoc.ContentStart, fDoc.ContentEnd);
using (MemoryStream ms = new MemoryStream())
tr.Save(ms, DataFormats.Rtf);
result = ms.ToArray();
return result;
private void InitializeHelper()
if (_helper == null)
//servername, databaseName, userName, userPassword
_helper = new HelperMySQL("localhost", "HN", "testUser", "removed");
private void InsertRow(int dgIndex)
//since the DataGrid DataContext is set to the DataTable,
//the DataTable is updated when data is modified in the DataGrid
//get last row
DataRow row = _dt.Rows[_dt.Rows.Count - 1];
//get data from DataTable
string supplierCode = row["supplier_Code"].ToString();
string supplierName = row["supplier_Name"].ToString();
string supplierAddress1 = row["supplier_Address1"].ToString();
string supplierAddress2 = row["supplier_Address2"].ToString();
string supplier_Zip = row["supplier_Zip"].ToString();
string supplier_City = row["supplier_City"].ToString();
string supplier_Url = row["supplier_Url"].ToString();
//convert RTF to string
byte[] memo = GetRichTextFromFlowDocument(inpSupplierMemo.Document);
InitializeHelper();
string result = string.Empty;
result = _helper.InsertTblSupplier(supplierCode, supplierName, supplierAddress1, supplierAddress2, supplier_Zip, supplier_City, supplier_Url, memo);
UpdateStatus(result);
private void UpdateRow(int dgIndex)
//when DataGrid SelectionChanged occurs, the value of '_currentDataGridIndex' is set
//to DataGrid SelectedIndex
//get data from DataTable
DataRow row = _dt.Rows[_currentDataGridIndex];
int supplierId = (int)row["supplier_Id"];
string supplierCode = row["supplier_Code"].ToString();
string supplierName = row["supplier_Name"].ToString();
string supplierAddress1 = row["supplier_Address1"].ToString();
string supplierAddress2 = row["supplier_Address2"].ToString();
string supplier_Zip = row["supplier_Zip"].ToString();
string supplier_City = row["supplier_City"].ToString();
string supplier_Url = row["supplier_Url"].ToString();
//convert RTF to string
byte[] memo = GetRichTextFromFlowDocument(inpSupplierMemo.Document);
InitializeHelper();
string result = string.Empty;
result = _helper.UpdateTblSupplier(supplierId, supplierCode, supplierName, supplierAddress1, supplierAddress2, supplier_Zip, supplier_City, supplier_Url, memo);
UpdateStatus(result);
private void UpdateStatus(string msg)
if (!String.IsNullOrEmpty(msg))
if (!msg.StartsWith("Error") && !msg.StartsWith("Status"))
textBoxStatus.Text = String.Format("Status: 0 (1)", msg, DateTime.Now.ToString("HH:mm:ss"));
Debug.WriteLine(String.Format("0 - Status: 1", DateTime.Now.ToString("HH:mm:ss"), msg));
else
textBoxStatus.Text = String.Format("0 (1)", msg, DateTime.Now.ToString("HH:mm:ss"));
Debug.WriteLine(String.Format("0 - 1", DateTime.Now.ToString("HH:mm:ss"), msg));
private void btnCreateTbl_Click(object sender, RoutedEventArgs e)
InitializeHelper();
//create table
string result = _helper.CreateTableSupplier();
UpdateStatus(result);
private void btnGetData_Click(object sender, RoutedEventArgs e)
GetData();
//update status
string msg = "Status: '" + _dt.Rows.Count + "' rows retrieved.";
UpdateStatus(msg);
private void SupplierCode_DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
DataGrid dg = (DataGrid)sender;
//set value
_currentDataGridIndex = dg.SelectedIndex;
GetMemo(dg.SelectedIndex);
private void btnSaveUpdate_Click(object sender, RoutedEventArgs e)
int rowIndex = _currentDataGridIndex;
if (_dt.Rows.Count > _dbRowCount)
InsertRow(SupplierCode_DataGrid.SelectedIndex);
else
UpdateRow(SupplierCode_DataGrid.SelectedIndex);
GetData();
// Make sure the eddited row in the datagrid is selected
SupplierCode_DataGrid.SelectedIndex = rowIndex;
SupplierCode_DataGrid.Focus();
private void btnInsertTestData_Click(object sender, RoutedEventArgs e)
string result = string.Empty;
GetData();
//only insert test data if no rows exist
if (_dt.Rows.Count == 0)
string memo1Str = @"\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033\fonttbl\f0\fnil\fcharset0 Calibri;
\*\generator Riched20 10.0.19041\viewkind4\uc1
\pard\sa200\sl276\slmult1\f0\fs22\lang9 Test Comments 1\par
";
//convert to byte[]
byte[] memo1 = ASCIIEncoding.Default.GetBytes(memo1Str);
string memo2Str = @"\rtf1\ansi\ansicpg1252\deff0\nouicompat\deflang1033\fonttbl\f0\fnil\fcharset0 Calibri;
\*\generator Riched20 10.0.19041\viewkind4\uc1
\pard\sa200\sl276\slmult1\f0\fs22\lang9 Test Comments 2\par
";
//convert to byte[]
byte[] memo2 = ASCIIEncoding.Default.GetBytes(memo2Str);
InitializeHelper();
result = _helper.InsertTblSupplier("1", "Acme 123", "51 my street", null, "12345", "Some City", "https://www.myUrl1.com", memo1);
UpdateStatus(result);
result = _helper.InsertTblSupplier("2", "Acme 456", "52 my street", null, "12345", "Some City", "https://www.myUrl2.com", memo2);
UpdateStatus(result);
GetData();
else
UpdateStatus("Status: Data exists in table-test data not added.");
资源:
rtf to textblock FlowDocumentScrollViewer【讨论】:
【参考方案3】:您的错误是由这一行引起的:
"supplier_Memo = '" + ContentSupplierMemo + "', " +
ContentSupplierMemo
包含类似于\rtf1\ansi\ansicpg1252...
的 RTF。当您将其连接到您的 SQL 语句时,反斜杠将直接发送到 MySQL,MySQL 将它们解释为转义字符并破坏您的数据。
解决方案是使用参数化 SQL。我不熟悉您的特定数据库包装器 (dbConnection.UpdateMySqlDataRecord();
),但大多数库都提供了一种向命令添加参数的方法。在 ADO.NET 中,它将是:
using var command = new MySqlCommand();
command.CommandText = @"UPDATE Supplier SET
supplier_Code = @supplierCode,
...
supplier_Memo = @supplierMemo
WHERE supplier_Id = @supplierId;";
command.Connection = connection;
command.Parameters.AddWithValue("@supplierCode", inpSupplierCode.Text);
...
command.Parameters.AddWithValue("@supplierMemo", ContentSupplierMemo);
command.Parameters.AddWithValue("@supplierId", valueSupplierId.Text);
command.ExecuteNonQuery();
最后,您使用Encoding.ASCII.GetString(ms.ToArray());
可能会损坏数据。您应该避免这种情况,只需将 ms.ToArray()
保存在 LONGBLOB
列中即可。
【讨论】:
以上是关于已解决如何从(MySQL)表中检索 RichText 内容到 WPF RichTextBox的主要内容,如果未能解决你的问题,请参考以下文章