简体   繁体   English

尝试从TimerCallback访问webbrowser控件时C#“InvalidCastException”

[英]C# “InvalidCastException” when trying to access webbrowser control from TimerCallback

Basically I have the same problem as this user: How to check for TrackBar sliding with mouse hold and release I fixed this using the first solution provided. 基本上我遇到与此用户相同的问题: 如何使用鼠标保持和释放检查TrackBar滑动我使用提供的第一个解决方案修复了此问题。 However, when the timer is called, I want to call InvokeScript on a webbrowser control. 但是,当调用计时器时,我想在Web浏览器控件上调用InvokeScript。 InvokeScript runs without an error, but the javascript function is never called. InvokeScript运行时没有错误,但从不调用javascript函数。 When I call this script from like a button clicked event handler, the function is called properly. 当我像按钮单击事件处理程序一样调用此脚本时,将正确调用该函数。

I found out that when I try to access properties from the webbrowser control (like MessageBox.Show(webBrowser1.DocumentText), this throws a InvalidCastException. 我发现当我尝试从webbrowser控件(如MessageBox.Show(webBrowser1.DocumentText))访问属性时,会抛出InvalidCastException。

// in constructor:
webBrowser1.AllowWebBrowserDrop = false;
webBrowser1.IsWebBrowserContextMenuEnabled = false;
webBrowser1.WebBrowserShortcutsEnabled = false;
webBrowser1.ObjectForScripting = this;
timer = new System.Threading.Timer(this.TimerElapsed);     

private void trackBar2_ValueChanged(object sender, EventArgs e)
{
        timer.Change(500, -1);
}
private void TimerElapsed(object state)
{
    this.webBrowser1.InvokeScript("jmp_end");
    MessageBox.Show(this.webBrowser1.DocumentText);
    timerRunning = false;
}
private void TimerElapsed(object state)
{
    WebBrowser brw = getBrowser();
    brw.Document.InvokeScript("jmpend");
    MessageBox.Show(brw.DocumentText);
    timerRunning = false;
}

Does anyone know what I am doing wrong here? 有谁知道我在做错了什么? Or is there another way to get the same result? 或者是否有其他方法可以获得相同的结果?

After comments about InvokeRequired, this sounds exactly like what I need.. But I can't get it working.. This is what I made from the sample code from C# System.InvalidCastException 在关于InvokeRequired的评论之后,这听起来就像我需要的那样..但是我无法让它工作..这是我从C#System.InvalidCastException的示例代码中得到的。

public delegate WebBrowser getBrowserHandler();
public WebBrowser getBrowser()
{
    if (InvokeRequired)
    {
        return Invoke(new getBrowserHandler(getBrowser)) as WebBrowser;
    }
    else
    {
        return webBrowser1;
    }
}

private void TimerElapsed(object state)
{
    WebBrowser brw = getBrowser();
    brw.Document.InvokeScript("jmpend");
    MessageBox.Show(brw.DocumentText);
    timerRunning = false;
}

What have I missed here? 我错过了什么?

The caller (the timer) is on a different thread than the control was created on. 调用者(计时器)与创建控件的线程不同。

See Control.InvokeRequired Property 请参见Control.InvokeRequired属性

Sample code that should address your issue is posted on this question: C# System.InvalidCastException 应该解决您的问题的示例代码发布在这个问题上: C#System.InvalidCastException

I had the same problem. 我有同样的问题。 As pointed out by Kevin P. Rice, the caller is on a diferente thread than the one the control was created on. 正如Kevin P. Rice指出的那样,调用者处于一个不同于创建控件的线程上。 A simple solution for this is to use this.Invoke() everytime the thread needs to interact with a control, therefore, if you desire to have the browser invoke a script, and you wish to call it from inside a separate thread, just do it like this: 一个简单的解决方案是每次线程需要与控件交互时使用this.Invoke() ,因此,如果您希望让浏览器调用脚本,并且您希望从单独的线程内部调用它,只需执行此操作它是这样的:

this.Invoke(new Action(() => { brw.Document.InvokeScript("jmpend"); }));

Or if you wish to change the property of the browse or another control within the form: 或者,如果您希望更改窗体中浏览或其他控件的属性:

this.Invoke(new Action(() => { button1.Enabled = false; }));

If the declaration of your thread is in another scope than that of your form, and you can't use the this keyword, you need to find a way to reference the current instance of the form. 如果您的线程声明在另一个范围而不是表单的范围内,并且您不能使用this关键字,则需要找到一种方法来引用表单的当前实例。

I hope this helps. 我希望这有帮助。 :) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM