WinForm文本框下拉选项间歇性异常崩溃问题求助
我有一个WinForm项目,给文本框设置下拉自动补全时,功能时而正常时而报错。尝试更换数据源(直接使用DataTable而非每次从数据库拉取)后,问题依旧。
问题代码
private void search_TextChanged(object sender, EventArgs e) { this.search.AutoCompleteMode = AutoCompleteMode.Suggest; this.search.AutoCompleteSource = AutoCompleteSource.CustomSource; var source = new AutoCompleteStringCollection(); string lang = StatementClump.SelectLanguage(3, language.Text); string lan = StatementClump.SelectLanguage(2, lang); // Retrieve the required data from the database and traverse it DataTable dt = StatementClump.SelectTable(2, lan, "rivenName", lan, search.Text, "%"); foreach (DataRow item in dt.Rows) { source.Add(item[0].ToString()); } // Setting the data source search.AutoCompleteCustomSource = source; }
抛出的异常信息
Exception thrown in Warframe Search.exe at 0x77195C57 (shell32.dll): 0xC0000005: An access violation occurred while reading location 0x00000060.
System.Collections.ListDictionaryInternal An attempt was made to read or write protected memory. This usually indicates that other memory is corrupted.
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
at System.Windows.Forms.Application.Run(Form mainForm)
at WindowsFormsApp3.Program.Main() in E:\wf\WindowsFormsApp3\Program.cs:line 19
line 19
Application.Run(new Form1());
问题原因
这个访问违规错误(0xC0000005),核心是TextChanged事件触发过于频繁,每次都重复初始化自动补全属性、创建新的AutoCompleteStringCollection并绑定,导致WinForms底层控件的UI消息循环(DispatchMessageW阶段)出现资源冲突或内存访问异常。
修复方案
1. 提前初始化基础配置
把自动补全的模式、数据源类型配置放到窗体初始化阶段,只执行一次,避免在TextChanged中反复修改控件属性。
2. 复用自动补全集合
不要每次创建新的AutoCompleteStringCollection,复用同一个集合对象,清空后添加新数据,减少控件内部资源的重复绑定操作。
3. 添加输入防抖
用Timer实现输入防抖,等用户停止输入一段时间后再执行数据库查询和补全列表更新,避免频繁触发导致的UI线程冲突。
修改后的代码示例
private AutoCompleteStringCollection _autoCompleteSource; private Timer _searchDelayTimer; public Form1() { InitializeComponent(); // 一次性初始化自动补全基础配置 search.AutoCompleteMode = AutoCompleteMode.Suggest; search.AutoCompleteSource = AutoCompleteSource.CustomSource; // 初始化并绑定补全集合 _autoCompleteSource = new AutoCompleteStringCollection(); search.AutoCompleteCustomSource = _autoCompleteSource; // 设置防抖Timer,延迟300ms触发(可根据需求调整) _searchDelayTimer = new Timer { Interval = 300 }; _searchDelayTimer.Tick += SearchDelayTimer_Tick; } private void search_TextChanged(object sender, EventArgs e) { // 每次输入时重置Timer,避免频繁触发查询 _searchDelayTimer.Stop(); _searchDelayTimer.Start(); } private void SearchDelayTimer_Tick(object sender, EventArgs e) { _searchDelayTimer.Stop(); string inputText = search.Text.Trim(); // 空输入时清空补全列表 if (string.IsNullOrEmpty(inputText)) { _autoCompleteSource.Clear(); return; } try { string lang = StatementClump.SelectLanguage(3, language.Text); string lan = StatementClump.SelectLanguage(2, lang); DataTable dt = StatementClump.SelectTable(2, lan, "rivenName", lan, inputText, "%"); // 复用集合,清空后添加新数据 _autoCompleteSource.Clear(); foreach (DataRow item in dt.Rows) { string itemContent = item[0]?.ToString(); if (!string.IsNullOrEmpty(itemContent)) { _autoCompleteSource.Add(itemContent); } } } catch (Exception ex) { // 可添加日志记录或提示 MessageBox.Show($"加载补全数据失败:{ex.Message}"); } } // 窗体关闭时释放Timer资源 protected override void OnFormClosed(FormClosedEventArgs e) { _searchDelayTimer?.Dispose(); base.OnFormClosed(e); }
内容的提问来源于stack exchange,提问作者moon

