C# 交叉线程操作无效:控件';表格1和x27;从创建它的线程以外的线程访问
我对C#相当陌生,但我一直在玩它来学习。到目前为止,我有一个很好的应用程序,可以启动屏幕保护程序和控制windows系统的音量 然而,我有一些麻烦,我不知道是什么问题。我已经在网站上遇到了很多类似的问题,但我认为这些问题都不适用于我的具体案例 所以我想从网络上控制应用程序。我的计划是让应用程序每隔几秒钟检查我网站上的一个网页上的一条命令。根据网站返回的内容,应用程序将执行不同的操作(静音、音量增大等),并将网站上的命令重置为空白。网站命令部分都是用PHP完成的,非常简单,这一部分没有问题 我创建了一个按钮,它调用一个函数来检查页面并执行操作。它工作得很好。但当我试图让它自动检查网站时,我发现了错误。我很确定这是因为我将检查和执行操作移动到了一个新线程。让我们继续看代码。这些不是完整的文件,但我认为你需要知道,以帮助。如果你还需要什么,请告诉我 表格1.csC# 交叉线程操作无效:控件';表格1和x27;从创建它的线程以外的线程访问,c#,multithreading,winforms,C#,Multithreading,Winforms,我对C#相当陌生,但我一直在玩它来学习。到目前为止,我有一个很好的应用程序,可以启动屏幕保护程序和控制windows系统的音量 然而,我有一些麻烦,我不知道是什么问题。我已经在网站上遇到了很多类似的问题,但我认为这些问题都不适用于我的具体案例 所以我想从网络上控制应用程序。我的计划是让应用程序每隔几秒钟检查我网站上的一个网页上的一条命令。根据网站返回的内容,应用程序将执行不同的操作(静音、音量增大等),并将网站上的命令重置为空白。网站命令部分都是用PHP完成的,非常简单,这一部分没有问题 我创建
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
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
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);
}
好的,基本上静音功能需要窗口手柄才能工作。但是,当我尝试从新线程获取窗口句柄时,它会抛出错误:
跨线程操作无效:从访问的控件“Form1”
线程,而不是创建它的线程
那我该怎么解决这个问题呢?我在这里读过其他答案,说您需要使用Invoke或Delegate,但我不确定它们是如何工作的,或者在哪里使用它们。我试图遵循其中一个答案,但我得到了更多的错误。在本例中,在方法内部编写invoke操作。然后您可以从控件的线程和其他线程访问
delegate IntPtr GetWindowHandleDelegate();
private IntPtr GetWindowHandle() {
if (this.InvokeRequired) {
return (IntPtr)this.Invoke((GetWindowHandleDelegate)delegate() {
return GetWindowHandle();
});
}
return this.Handle;
}
或者,如果您想避免委托地狱,您可以使用内置委托和lambda编写更多代码
private IntPtr GetWindowHandle() {
if (this.InvokeRequired)
return (IntPtr)this.Invoke((Func<IntPtr>)(GetWindowHandle));
return this.Handle;
}
private IntPtr GetWindowHandle(){
if(this.invokererequired)
返回(IntPtr)this.Invoke((Func)(GetWindowHandle));
把这个还给我;
}
试试这段代码,它肯定会对你有所帮助
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (s, e) => { };
bw.RunWorkerCompleted += (s, e) =>
{
//Call you windowsform method or anything which you want to do
};
bw.RunWorkerAsync();
你搜索了吗?请不要直接使用
Thread
s。对于长时间运行的I/O绑定操作,请使用async/await。对于长时间运行的CPU限制操作,请使用Task
s。感谢您教我如何使用谷歌。。。。你觉得我是怎么找到这个网站的?我又问了7个类似的问题,但没有一个有效。所以我问了我自己的问题,就像它告诉我的那样。每个问题都是关于从另一个线程更新UI的。但是我不想更新它,我只想获取一点信息(窗口句柄)并返回它。你接受的答案与他在第一条评论中链接到的问题@DavutGürbüz中接受的答案几乎相同。