为什么在通过Delegate.Target调用EventHandler.BeginInvoke时会看到跨线程异常?

时间:2015-12-10 19:20:55

标签: c# wpf winforms async-await invoke

我正在尝试编写一个扩展方法,它将简化跨线程事件处理。以下是我的想法,根据我的理解它应该起作用;但是当调用EndInvoke方法时,我得到一个跨线程异常......

using System;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;

namespace SCV {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {

        private static event EventHandler _Test;

        public static event EventHandler Test {
            add { MainWindow._Test += value; }
            remove{ MainWindow._Test -= value; }
        }

        private static async Task OnTest( ) {
            if ( MainWindow._Test != null )
                await MainWindow._Test.ExecuteAsync( null, EventArgs.Empty );
        }

        private LinearGradientBrush brshSomeBrush = new LinearGradientBrush(Colors.Red, Colors.Black, new Point(0, 0), new Point(1, 1));

        public MainWindow( ) {
            InitializeComponent( );
            MainWindow.Test += ( S, E ) => this.Background = this.brshSomeBrush;
                this.Loaded += async ( S, E ) => await MainWindow.OnTest( );
            }
    }

    static class Extensions {
        public static async Task ExecuteAsync( this EventHandler eH, object sender, EventArgs e ) {
            await Task.WhenAll( eH.GetInvocationList( ).Cast<EventHandler>( ).Select( evnt => Task.Run( ( ) => {
                System.Windows.Controls.Control wpfControl;
                System.Windows.Forms.Control formControl;
                Action begin = ( ) => evnt.BeginInvoke( sender, e, IAR => ( ( IAR as AsyncResult ).AsyncDelegate as EventHandler ).EndInvoke( IAR ), null );
                if ( evnt.Target is System.Windows.Controls.Control && !( wpfControl = evnt.Target as System.Windows.Controls.Control ).Dispatcher.CheckAccess( ) )
                    wpfControl.Dispatcher.Invoke( begin );
                else if ( evnt.Target is System.Windows.Forms.Control && ( formControl = evnt.Target as System.Windows.Forms.Control ).InvokeRequired )
                    formControl.Invoke( begin );
                else
                    begin( );
            } ) ) );
        }
    }
}

这仍然会引发异常的原因是什么?我怎么做错了?

1 个答案:

答案 0 :(得分:3)

你在正确的线程上调用委托 - 但委托本身然后调用evnt.BeginInvoke,它在线程池上执行evnt委托...所以你仍然最终执行< em>真正的底层委托(在这种情况下为_Test,将设置背景颜色)在非UI线程上。

您已经整理到了执行委托的正确线程 - 所以只需使用evnt(sender, e)执行它。