如何使用TextBox过滤DataGridView中MailKit加载的邮件数据
问题原因
- 核心问题:你填充DataGridView时直接调用
dataGridMessages.Rows.Add()方法插入行,没有为控件绑定DataSource,所以读取dataGridMessages.DataSource返回值为null,将空值赋值给BindingSource后自然没有数据可以过滤展示。 - 次要问题:每次
TextChanged事件触发时都新建BindingSource实例,属于不必要的重复操作,也容易出现上下文数据不一致的问题。
修复方案
方案一:使用DataTable作为绑定数据源(推荐,性能更优)
该方案修改原有填充逻辑,用标准数据绑定实现过滤,适合数据量较大的场景。
- 首先在窗体类中声明全局的DataTable和BindingSource对象:
// 全局变量定义,放在窗体类内部 private DataTable _mailDataTable; private BindingSource _mailBindingSource;
- 修改
ShowMessages方法的填充逻辑:
public void ShowMessages(ImapClient client) { // 初始化DataTable,列结构和你之前插入行的字段一一对应 _mailDataTable = new DataTable(); _mailDataTable.Columns.AddRange(new DataColumn[] { new DataColumn("Read", typeof(bool)), new DataColumn("Subject", typeof(string)), new DataColumn("From", typeof(string)), new DataColumn("Date", typeof(DateTimeOffset)), new DataColumn("HasAttachment", typeof(bool)), new DataColumn("Size", typeof(long)), new DataColumn("IsSelected", typeof(bool)), new DataColumn("UniqueId", typeof(uint)) }); var inbox = client.Inbox; inbox.Open(FolderAccess.ReadOnly); var uids = inbox.Search(SearchQuery.All); var items = inbox.Fetch(uids, MessageSummaryItems.Full | MessageSummaryItems.BodyStructure).Reverse(); foreach (var item in items) { // 按列顺序插入行数据,替换原有直接给DataGridView加行的逻辑 _mailDataTable.Rows.Add( read, item.Envelope.Subject, item.Envelope.From.ToString(), item.Envelope.Date, attach, item.Size, false, item.UniqueId.Id ); } // 绑定数据源到DataGridView _mailBindingSource = new BindingSource(); _mailBindingSource.DataSource = _mailDataTable; dataGridMessages.DataSource = _mailBindingSource; }
- 修改
TextChanged事件的过滤逻辑:
private void searchTxb_TextChanged(object sender, EventArgs e) { if (_mailBindingSource == null) return; if (string.IsNullOrWhiteSpace(searchTxb.Text)) { // 搜索框为空时清除过滤 _mailBindingSource.RemoveFilter(); return; } // 转义输入内容里的单引号,避免语法报错 var safeSearchText = searchTxb.Text.Replace("'", "''"); _mailBindingSource.Filter = $"Subject LIKE '%{safeSearchText}%'"; }
方案二:直接控制行可见性(适合小数据量场景)
如果不想修改原有填充逻辑,可以直接遍历DataGridView行,匹配搜索内容后设置行的可见性,数据量超过1000条时不推荐使用。
直接替换TextChanged事件代码即可:
private void searchTxb_TextChanged(object sender, EventArgs e) { var searchText = searchTxb.Text.Trim(); foreach (DataGridViewRow row in dataGridMessages.Rows) { // 跳过默认的新行模板 if (row.IsNewRow) continue; // 第2列是主题列,对应索引为1,和你之前插入行的顺序一致 var subject = row.Cells[1].Value?.ToString() ?? string.Empty; row.Visible = string.IsNullOrEmpty(searchText) || subject.Contains(searchText, StringComparison.OrdinalIgnoreCase); } }
注意事项
- 过滤用户输入内容时要做特殊字符转义,避免出现语法错误
- 如需同时过滤发件人、主题等多个字段,可修改Filter条件为
Subject LIKE '%xxx%' OR From LIKE '%xxx%'即可
内容的提问来源于stack exchange,提问作者eugenes
相关产品推荐
相关产品推荐

