0

考虑以下代码段:

if(form1.isLoggedIn) 
{             
    //Create a wait handle for the UI thread.
    //the "false" specifies that it is non-signalled
    //therefore a blocking on the waitone method.
    AutoResetEvent hold = new AutoResetEvent(false);

    filename = Path.Combine(Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData), DateTime.Now.ToString("ddMMyyhhmm") + "-" + form1.username);       

    Flow palm = new Flow(new FlowArguments(form1.username, filename), hold);

    System.Windows.Forms.NotifyIcon notifyIcon = new System.Windows.Forms.NotifyIcon();
    System.Windows.Forms.ContextMenuStrip notificationIconContext = new System.Windows.Forms.ContextMenuStrip();
    //Create a context menu strip
    ToolStripMenuItem contextAbout = new ToolStripMenuItem("About");
    ToolStripMenuItem contextExit = new ToolStripMenuItem("Exit");

    //properties of notifyicon that SO dosnt care for including a event handler for the mouse click events.


    //wait for the background thread to finish.                
    hold.WaitOne(Timeout.Infinite);

    MessageBox.Show("Thankyou, exiting...");
    form1.Dispose();                
} 

如您所见,FLOW 类非常简单。它只有一个正在运行的 Threading.Timer。因此,在 UI 线程上,我必须调用 WaitHandle.WaitOne() 方法,否则 UI 线程完成并因此结束应用程序..

我的目标:由于没有 GUI,我想创建一个通知图标。它可以工作,一切正常,除了我无法点击它并且它没有响应,这是因为它是在 UI 线程上创建的。我不能把它放在流类中,因为流类也在 UI 线程上(流类中的计时器在后台线程中)。

那么如何在 Flow 类中运行计时器时让我的 notifyicon 保持响应?我认为 waithandle 是我的解决方案,但由于它是一种阻塞方法,所以它不起作用。

还有其他想法/解决方案吗?

编辑:对 Rich 的回答的回应: Flow 类在后台线程上,一切都按照它应该的方式运行。但是,如果我不在 UI 线程中添加等待句柄,则 main() 在 UI 线程上完成,因此终止整个程序。(即使在后台线程上启用了计时器)。是否有另一种解决方案来等待处理?因为我必须把它留给 Flow 类来做它的事情。如果我把它拿出来,程序就会结束,如果我把它留在里面会阻塞 UI 线程,因此我的 notifyicon 不起作用。

4

4 回答 4

0

我不知道你的 Flow 对象是什么或它做了什么,但为什么它不能在另一个线程中工作而不阻塞 UI 线程?我认为通知图标是 UI 的一部分,因此需要在 UI 线程上,使其成为在另一个线程上运行的错误候选者。相比之下,您的 Flow 对象似乎正在执行您的应用程序的逻辑,这在另一个线程上产生更有意义。

于 2009-01-12T17:52:09.080 回答
0

标记为后台线程的活动线程将阻止程序退出。

于 2009-01-12T18:01:43.647 回答
0

我在字里行间读了一点,但我认为 Rich 是对的 - 您需要将后台处理移出 UI 线程:

  • 从上面的函数中删除 form1.dispose 调用 - 我想这是你唯一的表单,这就是为什么一旦你处理它,应用程序就会退出。
  • 异步调用流类-最简单的方法是在调用该函数的委托上调用 ThreadPool.QueueUserWorkItem() (尽管您实际上不应该使用线程池线程进行长时间运行的操作,但我怀疑它会在这种情况下受伤)
  • 一旦 flow 方法完成,回调 UI 线程让它知道。您可以通过使用合适的委托调用 form1.Invoke 来做到这一点
  • 在随后调用的函数中(即在 UI 线程上)关闭表单并退出您的应用程序

所以最终结果看起来像 3 个函数:

  • 上面的函数,它在后台开始处理,然后不等待就返回
  • 后台处理函数,在单独的线程上执行
  • 处理完成时在 UI 线程上调用的函数,用于关闭应用程序
于 2009-01-14T18:03:45.560 回答
0

正如ermau 所提到的,前台线程将阻止进程终止。

因此,一种解决方案是更改您的 Flow 类,使其使用前台线程。由于 Threading.Timer在系统提供的 ThreadPool 线程上执行,您将不得不使用其他东西。

如果您不想修改 Flow 类,另一种解决方案是创建一个等待句柄的前台线程(除了您的 UI 线程)。

Thread t = new Thread((ThreadStart)delegate { hold.WaitOne(); });
t.Start();

这将创建一个线程,该线程将阻塞,直到您的工作线程发出您的句柄“hold”信号,但不会阻塞您的 UI 线程。

于 2009-01-28T20:38:58.277 回答