如何在我的系统托盘应用程序中正确处理交叉线程问题?

时间:2011-07-14 15:34:05

标签: c# winforms multithreading

所以,我最近接手了一个现有的WinForms应用程序。我们需要将其更改为在系统托盘中运行的内容,但在用户需要时仍会弹出表单。没问题。根据这个问题:Mutex is being used to ensure only one copy of the app is running

该应用程序有3个主要组件:自定义应用程序上下文(myContext),它处理所有系统流浪的东西。 myContext创建一个名为Gozer(myGozer)的类的实例。 Gozer做了所有真正的工作。它在一个定时间隔内执行一系列操作(检查网络状态,如果我们有连接,那么它会执行其他一些操作。它还可以播放全球热核战争以获得乐趣)。让其他人知道通过一系列事件发生了什么。打开myForm时,myContext正在传递myGozer。

当我打开myForm时,我开始遇到各种各样的跨线程问题(任何时候以某种方式使用控件。就像操纵myListView一样)。我不清楚的是解决这个问题的最佳方法。我对线程知之甚少。我没有超大脑可以在30秒内理解线程。而且我没有任何人可以吃,以吸收他们的线程知识。

根据this question,我只需检查someControl.InvokeRequired,然后通过委托调用相关方法。这有效。但是现在每次我需要处理一个控件时,我面临着丢掉一堆代码的问题,这可能会引发一些可能在我头脑中校准不佳的警报。从表单退出应用程序时我也发现了一个问题;这会导致myContext中出现另一个跨线程异常。我不确定从myForm中退出应用程序是否合适,但此时还有哪些其他跨线程的疯狂等待着我?我觉得我正在为很多副作用引起的头痛做好准备。

我想我真的很担心在未来会产生一系列潜在的问题。或被要求扩展Gozer的功能,然后在需要myForm工作时创建更多问题。或者发现在运行时打开和关闭myForm会产生一堆额外的跨线程问题。或者该应用程序将导致一切爆炸。

还有其他我应该考虑或遗失的东西吗?

注意:这适用于.net 2.0应用,因此Jethro的解决方案无法在此处运行。也就是说,因为它不是那个很多地方我必须编写InvokeRequired逻辑,所以我就是这样做的。我很确定我将在明年升级到.net 3.5,下面建议的课程是我将如何处理他的问题。我将其标记为答案。

2 个答案:

答案 0 :(得分:4)

升级时,如果您不想编写扩展方法,可以选择其他方法。你需要熟悉lambda语法。这是一个例子:

myTextBox.Invoke( (Action) (() => myTextBox.Text = "text goes here"));

我通常不检查调用是否是必需的并且只是执行调用(通常知道您是否从与UI的线程不同的线程进行更新)。

注意:我曾经有类似的扩展方法,但厌倦了在我的所有项目中创建它或在需要添加到我的所有项目的库中创建它。这是一种“简单”的单行方式。

哦,如果你需要做多个操作,你也可以这样做内联:

myListView.Invoke( (Action) (() => 
    {
        myListView.Columns.Add("Column 1", -2, HorizontalAlignment.Left);
        myListView.Columns.Add("Column 2", -2, HorizontalAlignment.Left);
        myListView.Columns.Add("Column 3", -2, HorizontalAlignment.Left);
        myListView.Columns.Add("Column 4", -2, HorizontalAlignment.Center);
    }));

答案 1 :(得分:3)

这是您可以使用的扩展程序。不记得是我把它拿起来了。

这样称呼它。

this.InvokeEx(p=> p.txtbox.Text = "Rad");


public static class ControlExtensions
{
    public static TResult InvokeEx<TControl, TResult>(this TControl control,
                                                Func<TControl, TResult> func)
        where TControl : Control
    {
        return control.InvokeRequired
                ? (TResult)control.Invoke(func, control)
                : func(control);
    }

    public static void InvokeEx<TControl>(this TControl control,
                                            Action<TControl> func)
        where TControl : Control
    {
        control.InvokeEx(c => { func(c); return c; });
    }

    public static void InvokeEx<TControl>(this TControl control, Action action)
        where TControl : Control
    {
        control.InvokeEx(c => action());
    }
}