表单中的事件处理程序从c#中的线程调用

时间:2011-05-16 08:09:05

标签: c# winforms

我有一个多线程的应用程序,基于属性更改我想做一些操作,所以我为它创建了一个事件处理程序并从一个线程更改了属性,但仍然在事件触发时,我尝试访问表单事件处理程序方法中的元素visual studio抱怨跨线程访问已完成。我不明白为什么它被视为交叉线程。这是我的代码,

public delegate void AppStateChangedEventHandler(int st);
    public event AppStateChangedEventHandler AppStateChanged;
    private int appState;
    public int AppState
    {
        get { return this.appState; }
        set
        {
            this.appState = value;
            if (this.AppStateChanged != null)
            {
                this.AppStateChanged(value);
            }
        }
    }
    public void MainForm_AppStateChanged(int val)
    {
        if (val == 1)
        {                
            totDwn.Text = "00:00:00";
            totAct.Text = "00:00:00";                
        }
        else if (val == 0)
        {                
            tt.Reset();
            sw.Reset();
        }
    }

在我添加

的initializecomponent方法中
this.AppStateChanged += new AppStateChangedEventHandler(this.MainForm_AppStateChanged);

从线程内部我将appstate属性更改为

this.AppState = 1;

现在有两个问题

1)第一个也是重要的是vs抱怨即使我从事件处理程序访问GUI元素也正在执行交叉线程操作。(我知道如何使用所需的调用和委托来处理它,但我只需要知道为什么会这样)

2)VS警告AppStateChanged事件不属于Windows.form。

第一个问题是什么真的让我烦恼?对此有任何想法。

3 个答案:

答案 0 :(得分:6)

编辑:噢,我误解了你的问题。你想知道为什么VS抱怨?这是C#语言团队的一项设计决策,旨在避免跨线程访问表单控件的众多问题。

从技术上讲,没有理由不允许这样做,但最好以一致且易于修复的方式打破,而不是以奇怪的方式失败,因为两个线程操纵非线程安全控件,看似随意。


事件在触发它的线程(你的另一个线程)上执行,而不是在注册它的线程(主/ GUI线程)上执行。

要解决此问题,您必须确保在正确的线程上调用事件代码以允许访问GUI元素,这可以这样做:

public void MainForm_AppStateChanged(int val)
{
    if (this.InvokeRequired)
    {
        this.Invoke(new Action<int>(MainForm_AppStateChanged), val);
    }
    else
    {
        if (val == 1)
        {                
            totDwn.Text = "00:00:00";
            totAct.Text = "00:00:00";                
        }
        else if (val == 0)
        {                
            tt.Reset();
            sw.Reset();
        }
    }
}

答案 1 :(得分:1)

此问题的根本原因是您尝试访问控件之类的  totDwn&amp; totAct.Text在一个不同的线程中,然后一个线程创建它。 因此,您可以尝试使用以下代码来缓解此问题。 尝试在主应用程序中存储SynchronizationContext实例。我更喜欢OnLoad方法

SynchronizationContext Context = SynchronizationContext.Current;

之后在你的事件处理程序方法中你可以做

public void MainForm_AppStateChanged(int val)
{
    Context.Post((a)=> {

        if (val == 1)
        {                
            totDwn.Text = "00:00:00";
            totAct.Text = "00:00:00";                
        }
        else if (val == 0)
        {                
            tt.Reset();
            sw.Reset();
        }
    },null);
}

答案 2 :(得分:0)

事件处理程序在引发它们的线程上执行以保存上下文切换,这就是原因 你得到了例外。

相关问题