You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# WinForms中DrawString报错:异步改造后参数无效

WinForms打印发票抛出ArgumentException:无效参数(异步改造后出现)

问题详情

原本正常的WinForms项目,在将方法改为异步对接Supabase后,打印发票时抛出如下异常:

System.ArgumentException: Parameter is not valid.

   at System.Drawing.Graphics.CheckErrorStatus(Int32 status)

   at System.Drawing.Graphics.DrawString(String s, Font font, Brush brush, RectangleF layoutRectangle, StringFormat format)

   at Panaderia_Supabase.Forms.Cobranza.PrintPage(Object sender, PrintPageEventArgs e) in D:\Dev\Nueva carpeta\Panaderia-Supabase\Forms\Cobranza.cs:line 217

已确认所有传入DrawString的参数均不为空,排查发现问题出在Graphics对象上:
自定义的GetHeight方法中,运行时graphics.NativeGraphics为有效地址0x0000024f04c04230,但打印时该值变为0x0000000000000000(IntPtr.Zero)。

public float GetHeight(Graphics graphics)
{
    ArgumentNullException.ThrowIfNull(graphics, "graphics");
    if (graphics.NativeGraphics == IntPtr.Zero)
    {
        throw new ArgumentException("graphics");
    }
    SafeNativeMethods.Gdip.CheckStatus(SafeNativeMethods.Gdip.GdipGetFontHeight(new HandleRef(this, NativeFont), new HandleRef(graphics, graphics.NativeGraphics), out var size));
    return size;
}

尝试传入固定值仍无法解决,异常信息不够明确,寻求解决方案。

核心原因与解决方案

1. 异步操作导致UI线程上下文丢失

WinForms打印API(包括PrintPage事件)必须在UI线程执行。如果在PrintPage事件处理中调用了未正确同步上下文的异步方法,会导致Graphics对象的句柄失效。

  • 解决:避免在PrintPage事件内执行异步操作,提前在异步方法中获取好所有打印所需的数据,再触发打印流程。
  • 如果必须在打印流程中调用异步方法,使用Control.Invoke切回UI线程:
    private async void PrintButton_Click(object sender, EventArgs e)
    {
        // 提前异步获取数据,保留UI上下文
        var invoiceData = await _supabaseClient.Invoices.GetAsync().ConfigureAwait(true);
        // 数据就绪后触发打印
        printDocument.Print();
    }
    

2. Graphics对象被提前释放或GC回收

Graphics对象与当前打印上下文绑定,不能在异步流程中传递、保存或延迟使用,必须在PrintPage事件的同步代码块内直接使用。

  • 解决:确保所有依赖Graphics的操作(如DrawString、GetHeight)都在PrintPage事件的同步逻辑中完成,不要将Graphics对象传入异步方法。

3. 验证Graphics对象有效性

在使用Graphics对象前,除了检查非空,还需验证其未被释放:

private void PrintPage(object sender, PrintPageEventArgs e)
{
    if (e.Graphics.IsDisposed)
    {
        throw new InvalidOperationException("Graphics对象已被释放,无法执行打印操作");
    }
    // 后续打印逻辑
}

4. 确保异步方法保留UI上下文

在调用Supabase的异步方法时,使用ConfigureAwait(true)确保回到UI线程上下文,避免后续操作在非UI线程执行:

var data = await _supabaseClient.SomeTable.Select().GetAsync().ConfigureAwait(true);

补充说明

如果以上方案仍无法解决问题,请提供PrintPage方法的完整代码,以及触发打印的异步逻辑代码,以便进一步定位问题。

内容的提问来源于stack exchange,提问作者Lucas Rius

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 19:13:18