【问题标题】:Can I use 'await' calls while using System.Drawing.Graphics inside OnPrintPage event [closed]我可以在 OnPrintPage 事件中使用 System.Drawing.Graphics 时使用“等待”调用吗?
【发布时间】:2021-07-03 10:01:53
【问题描述】:

我正在尝试使用 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。 设法通过使用结果而不是等待呼叫来解决它,但我想知道是否有更好的解决方案。

var location = foo.CallWebAPI().Result;

【问题讨论】:

  • 事件处理程序应定义为async,以便您能够在其中使用await 关键字:protected override async void OnPrintPage(PrintPageEventArgs e) { ... }。但是您的示例代码中的foolocation 有什么关系...?你得到了什么例外?
  • 请将异常的消息和堆栈跟踪作为文本添加到您的问题中。
  • but I wonder if there is any better solution - 它是not really a solution

标签: c# .net asynchronous printing system.drawing


【解决方案1】:

不,你不能那样做。

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

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

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

您只能使用async 事件处理程序,前提是它不依赖于事件源在其事件被处理后将做什么。

【讨论】:

  • PrintPageEventArgs同步捕获您依赖的任何数据您调用await ...并从该方法返回之前。
  • @mm8 如何捕捉e.Graphics 的外观(我假设是克隆?),如果PrintDocument 已完成其打印工作流程,您将如何使用它?在OnPrintPage 中,您应该拥有在画布上实际绘制事物的代码。
  • 我不知道e.Graphics 本身,但我猜e.Graphics.VisibleClipBounds.X 是一个原始值类型。无论如何,我的观点是你可以像往常一样同步处理事件,然后调用远程 API。
  • @mm8 我举了一个误导性的例子,抱歉(已编辑问题)。我想在根据结果调用 API 后绘制一些东西。所以我需要功能齐全的图形对象。
  • 那么(再次)为什么不在调用异步方法之前同步访问事件参数?
【解决方案2】:

必须将事件处理程序定义为 async 才能在其中使用 await 关键字:

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

关于返回类型为voidasync 方法,指导原则是避免在事件处理程序中使用async void except,因此在事件处理程序中使用async void 只是很好:

Should I avoid 'async void' event handlers?

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

protected override async void OnPrintPage(PrintPageEventArgs e)
{
    //1. Capture the state
    var foo = e.Graphics.VisibleClipBounds.X;

    //2. Call async method
    var location = await foo.CallWebAPI();
}

【讨论】:

    猜你喜欢
    • 2017-09-30
    • 1970-01-01
    • 2011-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多