我有一个计时器,每次都验证一个条件,如果条件得到验证,只显示弹出窗体一次。我想并行验证所有实例,所以我使用parallel.for,但我有这个错误“跨线程操作无效:控制'CameraViewVS'访问从其创建的线程以外的线程。”在行“frm.WindowState = FormWindowState.Normal;”
这是我的代码:
public void timer1_Tick(object source, EventArgs e)
{
Parallel.For(0, nbre, l =>
{
cameraInstanceList[l].Start();
if (cameraInstanceList[l].MoveDetection == true)
{
//show the the form S once
foreach (Form S in Application.OpenForms)
{
var frm = S as Formes.CameraViewVS;
if (frm != null && frm.IP == cameraInstanceList[l].adresse)
{
cameraInstanceList[l].MoveDetection = false;
frm.WindowState = FormWindowState.Normal;
frm.Activate();
return;
}
}
f1 = new Formes.CameraViewVS(cameraInstanceList[l],
adresseIPArray[l]);
f1.Show(this);
}
}
);
答案 0 :(得分:0)
WinForm对象实例上的大多数属性都需要从创建它们的线程中访问。您可以使用Control.InvokeRequired属性来确定是否需要使用控件(或窗体)Invoke方法在UI线程上执行代码。
在主UI线程上创建大多数WinForm控件,而不是在任何线程池线程上也是一个好习惯。在WinForms应用程序中,您可以使用SynchronizationContext
来确保在UI线程上调用某些代码,例如创建表单。
编辑:已更改,以便在检测到移动后方法不会返回。
public void timer1_Tick(object source, EventArgs e)
{
// assume this is being called on the UI thread, and save the thread synchronization context
var uiContext = SynchronizationContext.Current;
Parallel.For(0, nbre, l =>
{
while (true)
{
Thread.Sleep(250); // <--- sleep for 250 ms to avoid "busy" wait
cameraInstanceList[l].Start();
if (cameraInstanceList[l].MoveDetection == true)
{
// capture instances used in closures below
var cameraInstance = cameraInstanceList[l];
var ipAdresse = adresseIPArray[l];
//show the the form S once
foreach (Form S in Application.OpenForms)
{
var frm = S as Formes.CameraViewVS;
if (frm != null)
{
// create delegate to be invoked on form's UI thread.
var action = new Action(() =>
{
if (frm.IP == cameraInstance.adresse)
{
cameraInstance.MoveDetection = false;
frm.WindowState = FormWindowState.Normal;
frm.Activate();
}
};
if (frm.InvokeRequired)
frm.Invoke(action);
else
action();
continue; // <--- go back to the top of the while loop
// and wait for next detection
}
}
// create delegate to create new form on UI thread.
var createNewFormCallback = new SendOrPostCallback((o) =>
{
f1 = new Formes.CameraViewVS(cameraInstance, ipAdresse);
f1.Show(this);
};
// and invoke the delegate on the ui thread
uiContext.Send(createNewFormCallback, null);
}
}
}
);
}
答案 1 :(得分:0)
Thomas非常接近正确答案,因为Every Control在不同的线程中运行。您应该只编写一个代码来进行控件正在使用的资源的上下文切换 线程..不要担心你在c sharp中有很多设施。只需使用BeginInvoke和Invoke,我希望你能够解决你的问题。写这个代替你的旧代码块..
var action = new Action(() =>
{
if (frm.IP == cameraInstance.adresse)
{
cameraInstance.MoveDetection = false;
frm.WindowState = FormWindowState.Normal;
frm.Activate();
}
};
if (frm.InvokeRequired)
frm.BeginInvoke(action);
else
frm.Invoke(action);