在c#中运行异步操作。 - 基本的。

时间:2009-01-12 17:44:34

标签: c# timer

请考虑以下代码段:

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线程上创建的。我不能把它放在流类中,因为Flow类也在UI线程上(Flow类中的计时器在后台线程中)。

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

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

编辑:对Rich的回答的回应:Flow类在后台线程上,一切都以它应该的方式运行。但是如果我不在UI线程中添加waithandle,则main()在UI线程上完成,从而终止整个程序。 (即使在后台线程上启用了计时器)。还有另一种等待手段的解决方案吗?因为我必须让它留给Flow类做它的事情。如果我把它拿出来,程序结束,如果我把它留在它中阻止UI线程因此我的notifyicon dosnt工作。

4 个答案:

答案 0 :(得分:0)

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我在这里读了一下这些行,但我认为Rich是对的 - 你需要从UI线程中移除后台处理:

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

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

  • 上面的函数,它在后台启动处理,然后返回而不等待
  • 后台处理函数,在单独的线程上执行
  • 处理完成时在UI线程上调用的函数,它关闭了应用程序

答案 3 :(得分:0)

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

因此,一种解决方案是更改Flow类,以便它使用前台线程。由于Threading.Timer executes on a ThreadPool thread supplied by the system,你将不得不使用别的东西。

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

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

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