自定义事件和线程

时间:2012-03-29 00:21:01

标签: c# multithreading events

我有两个不同的项目,在一个中,我有一个类定义了在某些条件下触发的自定义事件:

  public delegate void ButtonHandler(object myObject,
                                           GuitarArgs myargs);

        public event ButtonHandler OnButtonPress;

... other stuff ...

  GuitarArgs myArgs = new GuitarArgs( guitarState );
                if(OnButtonPress!= null)
                     OnButtonPress(this, myArgs);

然后在另一个项目中,我创建了这个类的一个实例并订阅了这个事件:

Guitar.OnButtonPress += Guitar_OnButtonPress;

然后事件正常触发,但它似乎在不同的线程上,因为当我尝试访问某些UI元素时,我收到一个错误:调用线程无法访问此对象,因为另一个线程拥有它。

抛出错误的代码是:

 void Guitar_OnButtonPress(object myObject, Guitar.GuitarArgs myargs)
        {
            GuitarCheck(myargs.State);
        }

        private void GuitarCheck(GuitarState getState)
        {
                if (getState.green) 
                {
                    VisualTreeHelper.HitTest(guitarCanvas, null,
                                             MyHitTestResult,
                                             new GeometryHitTestParameters(
                                                 new RectangleGeometry(new Rect(1, 411, 88, 78))));
                }
}

我该怎样做才能让这次运行?

谢谢。

3 个答案:

答案 0 :(得分:2)

您需要检查您的事件处理程序是否在非UI线程上运行,如果是,请在UI线程上调用它:

How to update the GUI from another thread in C#?

我想强调一下不太好的回答,它提供了一种使用扩展方法的非常优雅的方法。我在所有WinForms项目中使用它(并在WPF / Silverlight项目中使用变体)

https://stackoverflow.com/a/3588137/141172

答案 1 :(得分:1)

如果您使用的是WinForms this.Invoke(() => GuitarCheck(myargs.State));http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx

如果您使用的是WPF this.Dispatcher.Invoke(() => GuitarCheck(myargs.State));http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.invoke.aspx

答案 2 :(得分:0)

因此,您有一个名为OnButtonPress的事件,事件处理程序显然正在未托管VisualTreeHelper的线程上执行。对我来说最大的问题是......为什么?使用类似OnButtonPress的名称,它让我觉得它应该已经在UI线程上了。毕竟,这是一个按钮按下吗?那么为什么它是在另一个线程上执行的?

使用像InvokeBeginInvoke之类的编组操作是很好的,只要您知道为什么需要它以及它为您完成的任务。但是,你真的需要退后一步,确定一切都会导致你需要首先使用编组操作。这里可能存在一个更大的问题需要解决。