我最近通过Visual Studio中的Windows窗体应用程序模板创建了一个窗体应用程序。我认为该程序是使用多个线程自动创建的,将UI放在一个线程上以及另一个线程上的其他任何线程上。我没有在应用程序中放置任何代码来使用多线程。
无论我遇到并修复了here所描述的错误。抛出错误是因为我从下面的代码块中访问了一个UI对象。问题在于代码是从与UI的线程不同的线程运行的。
我想知道的是实际使用多线程的程序?如果是这样,我该如何防止这种情况发生。如果没有,这里发生了什么?
作为参考,我遇到此问题的代码与我初始化表单的同一个类。我遇到问题的那一行是在CheckUp函数的最后一行(已被更改为允许不同的线程访问)。 注意:代码的结构是移动到控制台应用程序,因此计时器方法和其他一些东西不那么犹太
public partial class Form : System.Windows.Forms.Form
{
public Form() {
InitializeComponent();
System.Timers.Timer actionTimer = new System.Timers.Timer(1000);
actionTimer.Elapsed += actionTimerTick;
actionTimer.AutoReset = true;
actionTimer.Enabled = true;
}
private void actionTimerTick(object sender, EventArgs e) {
CheckUp();
}
public void CheckUp() {
bool onlineStatus = GetOnlineStatus();
string status = (onlineStatus) ? "Online" : "Offline";
statusOutputLabel.Invoke((Action)(() => statusOutputLabel.Text = status ));
}
private static bool GetOnlineStatus() {
/*unrelated*/
}
}
答案 0 :(得分:2)
我想知道的是如何操作程序在一个线程上运行所有内容,以便我不必担心添加额外的代码来操作UI对象,
易。只是不要在Windows窗体应用程序中添加任何显式的创建线程代码。
我最近通过Visual Studio中的Windows窗体应用程序模板创建了一个窗体应用程序。该程序是使用多个线程自动创建的,将UI放在一个线程上以及另一个线程上的其他任何线程(我认为)。
Windows窗体应用程序模板创建的应用程序默认情况下是固有的单线程,因此不确定为什么您认为自己有其他线程。
如果您确实创建了与other post相关的其他工作线程,那么您应该使用Control.BeginInvoke
而不是Control.Invoke
,因为后者可能导致潜在的线程死锁。
像WinForms这样的GUI工具包可能总是单线程的。关于为什么要查看this article,请快速阅读。
KGH:
输入事件处理的问题是它往往在相反的方向运行到大多数GUI活动。通常,GUI操作从一堆库抽象的顶部开始并“向下”。我在我的应用程序中运行一个由一些GUI对象表示的抽象概念,所以我从我的应用程序开始,调用高级GUI抽象,调用较低级别的GUI抽象,调用丑陋的内容。工具包,然后进入操作系统。相比之下,输入事件从OS层开始,逐步向上调度抽象层,直到它们到达我的应用程序代码。 现在,由于我们使用抽象,我们自然会在每个抽象中单独进行锁定。不幸的是,我们有经典的锁定订单噩梦:我们有两种不同类型的活动,希望获得相反订单的锁定。 所以僵局几乎是不可避免的。 Golly, tell me more...
这就是为什么像Java AWT一样,WinForms也是单线程的。
答案 1 :(得分:2)
您正在使用System.Timer。 https://msdn.microsoft.com/en-us/library/system.timers.timer(v=vs.110).aspx
对于winforms应用程序,最好使用winforms ...
https://msdn.microsoft.com/en-us/library/system.windows.forms.timer(v=vs.110).aspx
它旨在支持单线程UI。 : -
Timer用于以用户定义的间隔引发事件。此Windows计时器专为使用UI线程执行处理的单线程环境而设计。它要求用户代码具有可用的UI消息泵,并始终在同一个线程中运行,或者将调用编组到另一个线程上。