跨线程操作无效:控件"Form1"是从不是在其上创建的线程的线程访问的 [英] Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on

查看:75
本文介绍了跨线程操作无效:控件"Form1"是从不是在其上创建的线程的线程访问的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对C#来说还很陌生,但是我一直在研究它.到目前为止,我有一个不错的应用程序,可以执行以下操作:启动屏幕保护程序并控制Windows系统音量.

Im pretty new to C# but I have been playing around with it to learn. So far I have a nice app that does things like starts up the screen saver and controls the windows system volume.

但是,我遇到了一些麻烦,而且不确定什么地方出了问题.我已经在网站上经历了很多类似的问题,但我认为这些问题均不适用于我的具体情况.

However I'm having some trouble and I'm not sure what is wrong. I have already gone through a bunch of similar questions on the site but I don't think any of them apply to my specific case.

所以我想从网络上控制应用程序.我的计划是让该应用每隔几秒钟检查一次我网站上的网页,以获取命令.根据网站返回的内容,应用将执行不同的操作(静音,调高音量等),并将网站上的命令重置为空白.网站命令部分全部用PHP完成,并且非常简单,该部分没有问题.

So I wanted to control the app from the web. My plan is to have the app check a webpage on my site for a command every couple seconds. Depending on what the site returns the app will do different things(mute, vol up, etc.) and reset the command on the website to blank. The website command part is all done in PHP and is quite simple, there is no problem with that part of it.

我创建了一个按钮,该按钮调用一个检查页面并执行操作的函数.工作正常.但是,当我尝试使其自动检查站点时,出现错误.我很确定这是因为我将检查移至新线程并执行了操作.因此,让我们继续进行代码.这些不是完整文件,而是我认为您需要了解的帮助信息.如果您还需要其他任何信息,请告诉我.

I created a button that calls a function that checks the page and performs the action. It worked fine. But when I tried to make it automatically check the site I'm getting errors. I'm pretty sure it is because I moved the check and perform action to a new thread. So lets move on to the code. These are not the full files but what I think you need to know to help. If you need anything more just let me know.

Form1.cs

public Form1(Boolean init = true)
    {
        if (init)
        {
            InitializeComponent(); //initialize UI
            startWebMonitor(); //starts web monitor thread for remote web commands
        }
    }

private void startWebMonitor()
    {
        Thread t = new Thread(WebMonitor.doWork);
        t.Start();
    }

public IntPtr getWindowHandle()
    {
        return this.Handle;
    }

WebMonitor.cs

WebMonitor.cs

public static void doWork()
    {
        while(true)
        {
            checkForUpdate();
            Thread.Sleep(1000);
        }
    }

private static void checkForUpdate()
    {
        lastCommand = getLastCommand();

        if (lastCommand.Equals(""))
        {
            //No Update
        }
        else
        {
            processCommand(lastCommand);
        }
    }

public static void processCommand(String command)
    {
        if(command.Equals("mute"))
        {
            VolumeCtrl.mute(Program.form1.getWindowHandle());
        }

        HTTPGet req2 = new HTTPGet();
        req2.Request("http://mywebsite.com/commands.php?do=clearcommand");
    }

VolumeCtrl.cs

VolumeCtrl.cs

private static IntPtr getWindowHandle()
    {
        Form1 form1 = new Form1(false); //false = do not initialize UI again
        return form1.getWindowHandle();
    }

    public static void mute(IntPtr handle)
    {
        SendMessageW(getWindowHandle(), WM_APPCOMMAND, getWindowHandle(), (IntPtr)APPCOMMAND_VOLUME_MUTE);
    }

好的,因此静音功能基本上需要窗口句柄才能起作用.但是,当我尝试从新线程获取窗口句柄时,它将引发错误:

Alright so basically the mute function requires the window handle in order to work. But when I try to get the window handle from the new thread it throws the error:

跨线程操作无效:控件"Form1"从 除了创建线程以外的其他线程.

Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on.

那么我该如何解决呢?我在这里还读过其他答案,说您需要使用Invoke或Delegate,但是我不确定它们如何工作或在何处使用它们.我尝试遵循其中一个答案,但出现了更多错误.

So how do I get around this? I have read other answers on here saying you need to use Invoke or Delegate but I'm not sure how those work or where to use them. I tried to follow one of the answers but I got even more errors.

推荐答案

在这种情况下,请在方法内部编写invoke操作.然后,您可以从控件的线程和其他线程进行访问.

In this case, write invoke operation inside of method. Then you can access both from control's thread and other threads.

delegate IntPtr GetWindowHandleDelegate();

private IntPtr GetWindowHandle() {

    if (this.InvokeRequired) {

        return (IntPtr)this.Invoke((GetWindowHandleDelegate)delegate() {

            return GetWindowHandle();

        });
    }

    return this.Handle;
}

或者,如果您想避免使用委托地狱,则可以使用内置的委托和lambda编写更少的代码.

or, if you want to avoid delegate hell, you could write in more few code with built-in delegate and lambda.

private IntPtr GetWindowHandle() {
    if (this.InvokeRequired)
        return (IntPtr)this.Invoke((Func<IntPtr>)(GetWindowHandle));

    return this.Handle;
}

这篇关于跨线程操作无效:控件"Form1"是从不是在其上创建的线程的线程访问的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆