2012-03-19 51 views
1

我在一个成员中得到了'跨线程操作无效',但在另一个成员中却没有,并且都属于同一个窗体,我相信这是同一个UI线程。这些成员是uxServerGroupuxServerListen。当我更改uxServerGroup.ValuesSecondary.Heading上的文本时,它工作正常,我没有遇到交叉线程异常。但是当我尝试启用uxServerListen按钮时,我确实会得到一个。 为什么为什么我没有为表单中的所有成员获得“跨线程操作无效”?

我应该注意到这两个组件都属于Krypton Toolkit,它们不是标准的Windows窗体。

下面的代码我有一个样本:

MainForm.cs:

public partial class MainForm : Form { 
    public MainForm() { 
     InitializeComponent(); 
     SomeClass.ObjectStateChanged += new ObjectStateEventHandler(SomeClass_ObjectStateChanged); 
    } 

    private void uxServerListen_Click(object sender, EventArgs e) { 
     uxServerListen.Enabled = false; 

     ClassHandler ch = ClassHandler(); 
     ch.Initialize(); 
    } 

    private void SomeClass_ObjectStateChanged(Enum e1, Enum e2) { 
     switch(e1) { 
      case E1.TypeA: 
       HandleTypeAObjectChanges(e1); 
       break; 
      case E1.TypeB: 
       HandleTypeBObjectChanges(e2); 
       break; 
     } 
    } 

    private void HandleTypeAObjectChanges(Enum e2) { 
     switch(e2) { 
      case E2.ModeA: 
       uxServerGroup.ValuesSecondary.Image = Resources.StatusSuccess16; 
       break; 
      case E2.ModeB: 
       uxServerGroup.ValuesSecondary.Image = Resources.StatusFailure16; 
       uxServerListen.Enabled = true; 
       break; 
     } 
    } 
} 

SomeClass.cs:

public delegate void ObjectStateEventHandler(Enum e1, Enum e2); 

public static class SomeClass { 
    public static event ObjectStateEventHandler ObjectStateChanged; 

    internal static E1 e1; 

    internal static void ObjectStateChanged(Enum e2) { 
     if(ConnectionStateChanged != null) { 
      ConnectionStateChanged(e1, e2); 
     } 
    } 
} 

ClassHandler.cs:

public class ClassHandler { 
    public ClassHandler() { 
     // (...) 
    } 

    public void Initialize() { 
     Thread thread = new Thread(new ThreadStart(SomeMethod)); 
     thread.Start(); 
    } 

    private void SomeMethod() { 
     SomeClass.ObjectStateChanged(E2.ModeB); 
    } 
} 

很多搜​​索后,我结束了固定这样的:

private void SomeClass_ObjectStateChanged(Enum e1, Enum e2) { 
     if(InvokeRequired) { 
      Invoke(new MethodInvoker(() => { 
       switch(e1) { 
        case E1.TypeA: 
         HandleTypeAObjectChanges(e2); 
         break; 
        case E1.TypeB: 
         HandleTypeBObjectChanges(e2); 
         break; 
       } 
      })); 
     } 
    } 

作为一个额外的问题,有人可以解释我这个(内MethodInvoker的东西):

new MethodInvoker(() => { /* (...) */ }) 
+0

因为只有当Winforms *知道*它是不安全的时候才会生成异常。它通过你的代码使用Handle属性来知道。像Enabled属性设置器一样。它不知道你自己添加的任何属性都是线程不安全的,它假定你做对了。 – 2012-03-20 01:20:24

回答

1

我在一个成员中得到'跨线程操作无效',但在另一个成员中没有'

需要专门检测无效的跨线程操作才能触发可用的异常。如果没有检测到,你将不会得到这个例外。但要小心:不要将它作为从另一个线程访问该属性的权限,它通常仍然不被允许,并且少数例外将记录为线程安全。

作为一个额外的问题,有人可以解释我这个(内MethodInvoker的东西):

new MethodInvoker(() => { /* (...) */ }) 

这将创建一个匿名的直线排列方式,并呼吁时,该/* (...) */语句将被执行。然后创建一个delegate以使该方法可调用,这就是传递给Invoke的方法。通常情况下,写起来可能会更简单一些,如下所示:

MethodInvoker foo =() => 
{ 
    ... 
}; 
// no part of the ... above has run yet 
if (!control.InvokeRequired) 
    foo(); // call foo directly 
else 
    control.Invoke(foo); // let the UI thread call foo 
+0

关于我的主要问题...虽然我使用线程,但我还使用事件/委托来将一些事件触发到“MainForm”。我认为这是线程安全的...... **我想这不是?**关于'MethodInvoker',明白了:)感谢您的不同方法:) – 2012-03-20 00:07:42

+1

@RicardoAmaral委托在调用它们的线程上运行。如果确保事件总是从UI线程中触发,事件处理程序也将在UI线程上运行,但是如果从另一个线程调用它,它将运行在同一个线程中。 – hvd 2012-03-20 00:12:26

相关问题