为什么我在通过 Delegate.Target 调用 EventHandler.BeginInvoke 时会看到跨线程异常?
Why am I seeing a Cross-thread exception when invoking EventHandler.BeginInvoke through Delegate.Target?
我正在尝试编写一个扩展方法来简化跨线程事件处理。以下是我的构想,根据我的理解,它应该可以工作;然而,当调用 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( );
} ) ) );
}
}
}
为什么还会抛出异常?我怎么做错了?
您在正确的线程上调用委托 - 但委托本身随后调用 evnt.BeginInvoke
,它在线程池上执行 evnt
委托...所以您最终仍然执行real 底层委托(在本例中 _Test
,将设置背景颜色)在非 UI 线程上。
您已经编组到要在其上执行委托的正确线程 - 因此只需使用 evnt(sender, e)
.
执行它
我正在尝试编写一个扩展方法来简化跨线程事件处理。以下是我的构想,根据我的理解,它应该可以工作;然而,当调用 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( );
} ) ) );
}
}
}
为什么还会抛出异常?我怎么做错了?
您在正确的线程上调用委托 - 但委托本身随后调用 evnt.BeginInvoke
,它在线程池上执行 evnt
委托...所以您最终仍然执行real 底层委托(在本例中 _Test
,将设置背景颜色)在非 UI 线程上。
您已经编组到要在其上执行委托的正确线程 - 因此只需使用 evnt(sender, e)
.