在 Windows Forms 應用程式中,為 TextBox 控制項提供類似百度搜尋框的自動完成下拉提示功能,支援從資料庫載入歷史輸入記錄,並在使用者離開控制項時自動儲存新輸入。
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Data.SqlClient;
public class AutoComplete
{
private readonly List _targetTextBoxes = new List();
private readonly Dictionary _dataSource =
new Dictionary();
private readonly SqlConnection _connection;
public AutoComplete(string connectionString)
{
_connection = new SqlConnection(connectionString);
LoadHistoryFromDatabase();
}
private void LoadHistoryFromDatabase()
{
try
{
_connection.Open();
using (var cmd = new SqlCommand("SELECT name, str FROM AutoComplete", _connection))
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
string key = reader["name"].ToString();
string value = reader["str"].ToString();
if (!_dataSource.ContainsKey(key))
_dataSource[key] = new AutoCompleteStringCollection();
_dataSource[key].Add(value);
}
}
}
finally
{
_connection.Close();
}
}
///
/// 為容器內所有 TextBox 啟用自動完成
///
public void AddAll(Control container)
{
foreach (Control ctrl in container.Controls)
{
if (ctrl is TextBox textBox)
Add(textBox);
}
}
///
/// 為單一 TextBox 設定自動完成
///
public void Add(TextBox textBox)
{
if (_targetTextBoxes.Contains(textBox)) return;
_targetTextBoxes.Add(textBox);
textBox.Leave += TextBox_Leave;
textBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
textBox.AutoCompleteSource = AutoCompleteSource.CustomSource;
if (!_dataSource.ContainsKey(textBox.Name))
_dataSource[textBox.Name] = new AutoCompleteStringCollection();
textBox.AutoCompleteCustomSource = _dataSource[textBox.Name];
}
private void TextBox_Leave(object sender, EventArgs e)
{
var textBox = sender as TextBox;
if (textBox == null || string.IsNullOrWhiteSpace(textBox.Text)) return;
string key = textBox.Name;
if (!_dataSource.ContainsKey(key))
_dataSource[key] = new AutoCompleteStringCollection();
// 避免重複儲存
if (!_dataSource[key].Contains(textBox.Text))
{
SaveToDatabase(key, textBox.Text);
_dataSource[key].Add(textBox.Text);
}
}
private void SaveToDatabase(string key, string value)
{
try
{
_connection.Open();
// 使用參數化查詢防止 SQL 注入
using (var cmd = new SqlCommand(
"INSERT INTO AutoComplete (name, str) VALUES (@name, @str)", _connection))
{
cmd.Parameters.AddWithValue("@name", key);
cmd.Parameters.AddWithValue("@str", value);
cmd.ExecuteNonQuery();
}
}
finally
{
_connection.Close();
}
}
///
/// 清除所有歷史記錄
///
public void ClearAll()
{
foreach (var collection in _dataSource.Values)
collection.Clear();
try
{
_connection.Open();
using (var cmd = new SqlCommand("DELETE FROM AutoComplete", _connection))
cmd.ExecuteNonQuery();
}
finally
{
_connection.Close();
}
}
// 其他方法:Delete, DeleteAll 等...
}
public partial class MainForm : Form
{
private AutoComplete _autoComplete;
public MainForm()
{
InitializeComponent();
string connStr = "Data Source=.;Initial Catalog=TestDB;Integrated Security=True";
_autoComplete = new AutoComplete(connStr);
_autoComplete.AddAll(this); // 為表單上所有 TextBox 啟用
}
}
AutoCompleteStringCollection。SqlParameter 防止 SQL 注入。using 區塊確保 SqlCommand、SqlDataReader 正確釋放。CREATE TABLE AutoComplete (
id INT IDENTITY(1,1) PRIMARY KEY,
name NVARCHAR(100) NOT NULL, -- 對應 TextBox.Name
str NVARCHAR(500) NOT NULL, -- 使用者輸入內容
created_at DATETIME DEFAULT GETDATE()
);
CREATE INDEX IX_AutoComplete_name ON AutoComplete(name);