仅当从计时器调用函数时无效转换

问题描述

我正在尝试做一个从网站读取字符串的程序,将其发送到另一个网站。第一个读取字符串的过程正常工作,以及将字符串发送到其他工作的函数,但是从计时器调用函数时出现问题..

这是我的代码的一部分:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using CefSharp;
using CefSharp.WinForms;
using CefSharp.WinForms.Internals;

namespace CodePinger
{
    public partial class Form1 : Form
    {
        public bool login = true;
        private static System.Timers.Timer TimerCheck;
        public Form1()
        {
            InitializeComponent();
            TimerCheck = new System.Timers.Timer(5000);
            TimerCheck.Elapsed += new ElapsedEventHandler(CheckEvent);
            TimerCheck.AutoReset = true;
            CheckForIllegalCrossthreadCalls = false;
            webbrowser1.ScriptErroRSSuppressed = true;
            chromiumWebbrowser1.Load("https://firstwebsite.com");
            webbrowser1.Navigate("http://secondwebsite.com");
        }
        private async void CheckEvent(Object source,ElapsedEventArgs e)
        {
            if (login) { 
                string script = "document.getElementById('SecondSdisP').innerText;";
                JavascriptResponse jr = chromiumWebbrowser1.EvaluateScriptAsync(script).Result;
                if (jr.Success)
                {
                    if (jr.Result.ToString().Contains("01"))
                    {
                        label2.ForeColor = Color.Red;
                        label2.Text = jr.Result.ToString();
                        sendCode(jr.Result.ToString());
                    }
                }
                else
                {
                    label2.ForeColor = Color.Black;
                    label2.Text = "no data";
                }
                label4.Text = timer.ToString();
            }
        }
        private void button2_Click(object sender,EventArgs e)
        {
            TimerCheck.Enabled = true;
            TimerCheck.Start();
            button2.Enabled = false;
        }
        public void sendCode(string code)
        {
            string msg = "";
            if (code == "1") msg = "1 coda";
            else msg = code.ToString() + " code";
            var textarea = webbrowser1.Document.GetElementsByTagName("textarea")[0];
            textarea.InnerHtml = msg;
            textarea.Focus();
            var allsvg = webbrowser1.Document.GetElementsByTagName("svg");
            foreach (HtmlElement svg in allsvg)
            {
                if (svg.GetAttribute("className").Contains("-send"))
                {
                    svg.InvokeMember("click");
                    break;
                }
            }
        }
        private void button4_Click(object sender,EventArgs e)
        {
            sendCode("1");
        }
    }
}

同样在我启动计时器后,如果我单击 button4 来测试该功能,它可以正常工作。而不是从计时器调用

错误是:

system.invalidCastException
  HResult=0x80004002
  Message=Specified cast is not valid.
  Source=System.Windows.Forms
  StackTrace:
   at System.Windows.Forms.UnsafeNativeMethods.IHTMLDocument2.GetLocation()
   at System.Windows.Forms.Webbrowser.get_Document()
   at CodePinger.Form1.sendCode(String code) in C:\Users\Flynns82\source\repos\CodePinger\Form1.cs:line 105
   at CodePinger.Form1.<CheckEvent>d__9.MoveNext() in C:\Users\Flynns82\source\repos\CodePinger\Form1.cs:line 63

指示的行是:

105) var textarea = webbrowser1.Document.GetElementsByTagName("textarea")[0];
63) sendCode(jr.Result.ToString());

有人能解释一下是什么问题吗?

解决方法

您的问题很可能是您试图从非 STA 线程(也称为“UI 线程”)访问 WebBrowser

当您使用 button4_click 处理程序时,您的代码在 STA 线程上运行(默认情况下),但是,当时间事件处理程序被回调时,它发生在不同的线程(不是 STA 线程)中,因此您将有如果您不“调用”回 STA,则调用/访问 ActiveX/组件(驻留在 STA 线程中)上的属性时会出现问题。

我建议您查看以下 SO Question: STA vs MTA 以获得技术说明。

要解决调用问题,请查看以下 SO Question: Automating the InvokeRequired code pattern

另一方面浏览器暴露了一个 NavigateComplete 事件,你不需要花时间检查页面何时加载,只需将自己挂钩到该事件并在导航后等待它,DOM 将此事件触发后稳定。