Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/292.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在我的systray应用程序中正确处理跨线程问题?_C#_Winforms_Multithreading - Fatal编程技术网

C# 如何在我的systray应用程序中正确处理跨线程问题?

C# 如何在我的systray应用程序中正确处理跨线程问题?,c#,winforms,multithreading,C#,Winforms,Multithreading,所以,我最近接管了一个现有的WinForms应用程序。我们需要将其更改为在系统托盘中运行,但当用户需要时仍会弹出表单。没问题。根据这一问题: 该应用程序有3个主要组件:自定义应用程序上下文(myContext),用于处理所有系统内容。myContext创建一个名为Gozer(myGozer)的类的实例。戈泽做所有真正的工作。它在一段时间间隔内执行一系列操作(检查网络状态,如果我们有连接,它会做一些其他事情。它也会玩全球热核战争以自娱自乐)。通过一系列的活动让其他人知道发生了什么。当myForm打

所以,我最近接管了一个现有的WinForms应用程序。我们需要将其更改为在系统托盘中运行,但当用户需要时仍会弹出表单。没问题。根据这一问题:

该应用程序有3个主要组件:自定义应用程序上下文(myContext),用于处理所有系统内容。myContext创建一个名为Gozer(myGozer)的类的实例。戈泽做所有真正的工作。它在一段时间间隔内执行一系列操作(检查网络状态,如果我们有连接,它会做一些其他事情。它也会玩全球热核战争以自娱自乐)。通过一系列的活动让其他人知道发生了什么。当myForm打开时,myContext正在传入myGozer

当我打开我的表单时,我开始遇到各种各样的跨线程问题(无论何时以某种方式使用控件,比如操纵myListView)。我不清楚的是处理这个问题的最佳方法。我对穿线知之甚少。我没有一个超大的大脑可以在30秒内理解线程。我周围没有人可以吃东西来吸收他们对穿线的高超知识

根据,我可以简单地检查
someControl.invokererequired
,然后通过委托调用有问题的方法。这很有效。但现在每当我需要处理一个控件时,我都要面对在前面扔下一堆代码的问题,这可能会在我的脑海中触发一些校准不当的警钟。我从表单中退出应用程序时也发现了一个问题;这将导致myContext中出现另一个跨线程异常。我不确定从myForm中退出应用程序是否合适,但现在还有什么其他的跨线程疯狂在等着我呢?我觉得我有很多副作用引起的头痛

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

还有什么我应该考虑或遗漏的吗


注意:这是针对.NET2.0应用程序的,因此Jethro的解决方案在这里不起作用。也就是说,因为我需要编写invokererequired逻辑的地方不多,所以我就要这么做。我很确定我会在明年把它升级到.NET3.5,下面建议的课程是我如何处理这个问题的。因此,我将其标记为答案。

这是您可以使用的扩展名。我想不起来是我捡到的

这样说吧

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());
    }
}
this.InvokeEx(p=>p.txtbox.Text=“Rad”);
公共静态类控件扩展
{
公共静态TResult InvokeEx(此TControl控件,
Func Func)
其中TControl:Control
{
返回控件。需要调用
?(TResult)控件。调用(func,控件)
:func(控制);
}
公共静态void InvokeEx(此TControl控件,
行动(func)
其中TControl:Control
{
InvokeEx(c=>{func(c);返回c;});
}
公共静态void InvokeEx(此TControl控件、操作)
其中TControl:Control
{
InvokeEx(c=>action());
}
}

当您进行升级时,如果您不想编写扩展方法,还有一种替代方法。不过,您需要熟悉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);
    }));

这是针对.NET2.0的。这看起来很有趣,让我看看该怎么办。哇,我把最后的评论删掉了。我最初写的是“2.0,我不能使用扩展方法”,但后来我在一个4.0项目中玩弄了这一点,有点走上了一条奇怪的道路,对一些事情感到困惑,更不用说了。但我不能这么做。不过,我真的很喜欢这个答案。扩展方法只是静态方法的语法糖。您应该仍然能够在2.0中复制该行为,但必须手动调用静态方法并将控件作为第一个参数传入。另外,您可能需要创建自己版本的Action和Func委托(非常确定它们是3.0或3.5的一部分)。@peacedog:事实上,作为一个补充,似乎有些人已经找到了让扩展方法在.Net 2.0:或此处工作的方法:@Jason Down-巧合的是,我在午餐前找到了一个。我不知道;聪明的解决方法。我只是认为检查invokererequired很重要。因为我肯定是从另一个线程更新UI,所以我想我会跳过它。这种方法没有坏处吗?我很喜欢这种替代调用方法。这似乎是共识。关于这个话题,这里还有另外一个问题: