C# WinForms:仅在Timer.ElapsedEventHandler中触发System.InvalidCastException异常
我之前也碰到过一模一样的问题!原因其实很简单——你用的System.Timers.Timer的Elapsed事件是在后台线程触发的,而WinForms的所有UI控件(包括WebBrowser)都只能在创建它们的UI线程上操作,跨线程直接访问就会抛出System.InvalidCastException这类异常。
下面给你两个靠谱的解决方案,选一个适合你的就行:
解决方案1:改用WinForms自带的Timer(最省心)
直接把System.Timers.Timer换成System.Windows.Forms.Timer,这个定时器的Tick事件本身就在UI线程执行,完全不用处理跨线程问题,代码写起来也更简洁:
// 可以在窗体设计器里拖一个Timer控件,也可以手动创建 private System.Windows.Forms.Timer _autoClickTimer; private void Form_Load(object sender, EventArgs e) { _autoClickTimer = new System.Windows.Forms.Timer(); _autoClickTimer.Interval = 20000; // 设置为20秒 _autoClickTimer.Tick += AutoClickTimer_Tick; _autoClickTimer.Start(); } private void AutoClickTimer_Tick(object sender, EventArgs e) { // 这里直接操作WebBrowser就行,因为是在UI线程 var logoutLink = webBrowser2.Document?.GetElementById("link_logout"); logoutLink?.InvokeMember("click"); }
解决方案2:用Invoke切换到UI线程(如果坚持用System.Timers.Timer)
如果你因为某些原因必须保留System.Timers.Timer,那就要在Elapsed事件里通过Invoke方法把操作切换到UI线程,确保控件操作在正确的线程上执行:
private System.Timers.Timer _autoClickTimer; private void Form_Load(object sender, EventArgs e) { _autoClickTimer = new System.Timers.Timer(20000); _autoClickTimer.Elapsed += AutoClickTimer_Elapsed; _autoClickTimer.Start(); } private void AutoClickTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { // 先检查是否需要跨线程调用 if (webBrowser2.InvokeRequired) { // 用Invoke把点击操作委托给UI线程执行 webBrowser2.Invoke(new Action(() => ClickLogoutLink())); } else { ClickLogoutLink(); } } // 把点击逻辑抽成单独方法,复用起来更方便 private void ClickLogoutLink() { var logoutLink = webBrowser2.Document?.GetElementById("link_logout"); logoutLink?.InvokeMember("click"); }
额外提醒
记得在窗体关闭的时候停止并释放定时器,避免内存泄漏:
private void Form_FormClosing(object sender, FormClosingEventArgs e) { _autoClickTimer?.Stop(); _autoClickTimer?.Dispose(); }
内容的提问来源于stack exchange,提问作者dee7kay
相关产品推荐
相关产品推荐

