我正在编写一个用于监控的GUI应用程序,我想就它的逻辑提供一些建议。基本上所有应用程序需要做的是每x分钟连接一个远程服务器,检查是否有更改,如果有更改,请对它们进行操作(更新本地数据库等等,具体取决于更改)。
我的第一个想法是:
我的主要问题是从Timer调用Worker,因为我将Worker添加到Form中,现在它们位于不同的线程上(这是正确的描述吗?)然后传递结果是一个类似的问题。我正在阅读有关代表的内容,但仍不确定何时以及如何使用,以及首先是否真的有必要。我需要bgWorker和Timer吗?我是否需要自定义事件,或者我可以使用Switch(结果)在workDone中完成所有工作吗?这个一般原则首先是好的,也许有更好的东西,我正在重新发明轮子?提前谢谢!
答案 0 :(得分:2)
从架构的角度来看:
消息队列可以解耦应用程序的各个位。您可以在Windows窗体应用程序中依赖Windows为您创建和管理的消息队列。 Google for PostMessage / GetMessage等。这通常称为“消息传递”。
典型的Arcitecture
所以它看起来像这样:
App - >请求队列 - >处理引擎 - >结果队列 - >应用
处理引擎可以在同一个应用程序中,在同一个线程上,也可以在不同的线程/进程中(甚至是不同的机器)。
您可以使用简单队列:说Queue<string>()
(只要您使用锁来访问它)或增加复杂性或更复杂/更多功能的队列。
天真战略和其他解决方案的问题......要考虑的事情:
示例代码
object oLock = new object();
Queue<string> requests = new Queue<string>();
Queue<string> responses = new Queue<string>();
Thread mThread;
AutoResetEvent mEvent = new AutoResetEvent(false);
public Form1()
{
InitializeComponent();
mThread = new Thread(ProcessingEngine);
mThread.IsBackground = true;
mThread.Start();
}
private void ProcessingEngine()
{
string result;
string request = null;
while (true)
{
try
{
mEvent.WaitOne();
lock (oLock)
{
request = requests.Dequeue();
}
var wc = new WebClient();
result = wc.DownloadString(request);
lock (oLock)
{
responses.Enqueue(result);
}
}
catch (Exception ex)
{
lock (oLock)
{
responses.Enqueue(ex.ToString());
}
}
}
}
private void timer1_Tick(object sender, EventArgs e)
{
lock (oLock)
{
//Stick in a new request
requests.Enqueue("http://yahoo.com");
//Allow thread to start work
mEvent.Set();
//Check if a response has arrived
if (responses.Any())
{
var result = responses.Dequeue();
listBox1.Items.Add(result.Substring(1,200));
}
}
}
}
答案 1 :(得分:0)
如果您使用System.Windows.Forms.Timer
代替System.Threading.Timer
,您的Tick
处理程序将从Form的消息循环中调用,您将拥有对所有控件的完全访问权限 - 可以安全地调用bgWorker.RunWorkerAsync()。至于检索结果 - 也可以从消息循环线程中调用RunWorkerCompleted
,您可以在这里安全地更新您的UI。
答案 2 :(得分:0)
解决方案很简单 - INVOKE回到主线程。这是winform控件上的Invoke方法。这基本上会将执行线程更改为UI线程,并允许您操作UI。
这样做“阻止”(即每次控制一次,但有新闻时一次)。