【问题标题】:event handler in form getting invoked from a thread in c#从 C# 中的线程调用表单中的事件处理程序
【发布时间】:2011-05-16 08:09:05
【问题描述】:

我有一个多线程应用程序,并且基于 propertychange 我想做一些操作,所以我为此创建了一个事件处理程序并从一个线程更改了属性,但是当事件触发时,我仍然尝试访问表单事件处理程序方法 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 的一部分。

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

【问题讨论】:

标签: c# winforms


【解决方案1】:

编辑:哦,我误读了你的问题。你想知道为什么 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();
        }
    }
}

【讨论】:

  • ",但最好以一致且易于修复的方式中断,而不是由于两个线程操纵非线程安全控制而以看似随机的奇怪方式失败“我不明白这个@SirViver 你可以吗解释一下。你是说创建自定义事件处理程序不好。
  • @swordfish:不,这与自定义事件处理程序无关。 任何代码尝试修改在另一个线程上创建的控件都会导致此错误,这是一件好事,因为当您尝试访问它时,它会立即以一种非常可预测的方式失败。允许跨线程控制访问(没有 Invoke 或特殊的同步工作)可能会在 95% 的时间内工作,然后巧妙地(或不那么巧妙地)随机地完全崩溃。使用当前的实现,开发人员必须立即正确地执行此操作,从长远来看可以避免很多麻烦。
【解决方案2】:

这个问题的根本原因是你试图访问像这样的控件 totDwn & 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);
}

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2013-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-08
      相关资源
      最近更新 更多