繁体   English   中英

从C#中的线程调用形式的事件处理程序

[英]event handler in form getting invoked from a thread in c#

我有一个多线程应用程序,并且基于属性更改,我想执行一些操作,因此我为此创建了一个事件处理程序,并从线程中更改了该属性,但是仍然在事件触发时,我尝试访问该表单中的表单元素事件处理程序方法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元素也正在执行跨线程操作。(我知道如何使用需要的invoke和委托来处理此问题,但是我只需要知道为什么会这样)像这样)

2)VS不断警告AppStateChanged事件不是Windows.form的一部分。

第一个问题是什么真的让我感到恼火? 任何想法。

编辑:天哪,我看错了你的问题。 您想知道为什么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();
        }
    }
}

此问题的根本原因是,您试图在另一个线程(然后创建该线程)中访问诸如toDDwn和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);
}

事件处理程序在引发它们的线程上执行,以保存上下文切换,这就是为什么要获取异常的原因。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM