我可以在 OnPrintPage 事件中使用 System.Drawing.Graphics 时使用“await”调用吗

问题描述

我正在尝试使用 System.Drawing.Printing.PrintDocument OnPrintPage 方法打印文档页面

我需要调用外部服务来获取打印当前页面所需的测量值。当我调用 API 时,图形对象似乎由于多线程(?)而被锁定,并在我从 API 获取数据后尝试使用它时抛出异常。在打印文档之前无法获取数据。有什么办法可以避免这种阻塞吗?

    protected override async void OnPrintPage(PrintPageEventArgs e)
    {
        var location = await foo.CallWebAPI();

        //Do something with Graphics 
        e.Graphics.DrawLine(....);
        //ERROR - Argument Exception
        
    }

编辑:

我忘记在签名中添加异步,但这不是我的问题的一部分。调试器中的图形对象似乎在等待调用后被锁定/处置。它在任何图形字段上显示 ArgumentException。 设法通过使用 Result 而不是等待调用解决它,但我想知道是否有更好的解决方案。

var location = foo.CallWebAPI().Result;

解决方法

不,你不能那样做。

您可以通过将 async 添加到您的处理程序签名来编译它,但您将无法有意义地处理该事件。

当您的 async 事件处理程序遇到其 first incomplete await 时,执行将返回给调用者(引发事件的对象)。此时,事件源确定您已经完全处理了该事件,因此它可以继续执行其他操作,包括在引发事件之前清理它分配的 Graphics 对象。

当您最终开始使用该 Graphics 对象时,不仅它已被事件源处理,而且事件源很可能不在适合您的事件处理操作的状态.

您只能使用 async 事件处理程序,当它不依赖于处理其事件后事件源将执行的操作时。

,

事件处理程序必须定义为 async 以便您能够在其中使用 await 关键字:

protected override async void OnPrintPage(PrintPageEventArgs e) { ... }. 

关于返回类型为 asyncvoid 方法,准则是在事件处理程序中使用时避免 async void except 所以使用 {{1 }} 在事件处理程序中就好了:

Should I avoid 'async void' event handlers?

async void before 捕获任何状态可能也是一个想法,PrintPageEventArgs 异步方法并从事件处理程序返回:

await