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

PowerShell WinForms多行表头ListView实现及DrawString参数错误排查

实现带两行文本列头的ListView(PowerShell版)

问题说明

需求是实现支持两行文本的ListView列头,在C#中通过DrawColumnHeader事件可以正常完成,但在PowerShell中遇到两个问题:

  • 调用e.Graphics.DrawString时触发类型转换错误:Cannot convert argument "point", with value: "{X=60,Y=8,Width=60,Height=8}", for "DrawString" to type "System.Drawing.PointF",尽管DrawString确实支持RectangleF参数重载
  • 使用Visual Studio PowerShell Form时无报错,但列无法显示

错误原因

  1. PowerShell在解析.NET方法重载时存在歧义,将Rectangle实例错误匹配到需要PointF的重载,导致类型转换失败
  2. 原代码未设置列头宽度,ListView默认列宽为0,因此列不可见

修复后的代码

Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing

$form = New-Object System.Windows.Forms.Form
$form.Text = "ListView with Custom Column Headers"
$form.Size = New-Object System.Drawing.Size(400, 300)

$listView1 = New-Object System.Windows.Forms.ListView
$listView1.Location = New-Object System.Drawing.Point(10, 10)
$listView1.Size = New-Object System.Drawing.Size(380, 200)
$listView1.View = [System.Windows.Forms.View]::Details
$listView1.OwnerDraw = $true

# 添加列并设置宽度
$columnHeader1 = New-Object System.Windows.Forms.ColumnHeader
$columnHeader1.Text = " "  # 占位文本,自定义绘制会覆盖
$columnHeader1.Width = 150
$columnHeader1.Tag = "First Line`nSecond Line"

$columnHeader2 = New-Object System.Windows.Forms.ColumnHeader
$columnHeader2.Text = " "
$columnHeader2.Width = 150
$columnHeader2.Tag = "Third Line`nFourth Line"

$listView1.Columns.AddRange(@($columnHeader1, $columnHeader2))

# 添加演示项
$listView1.Items.Add("Item 1") | Out-Null
$listView1.Items[0].SubItems.Add("Subitem 1") | Out-Null

$listView1.Items.Add("Item 2") | Out-Null
$listView1.Items[1].SubItems.Add("Subitem 2") | Out-Null

$listView1.Items.Add("Item 3") | Out-Null
$listView1.Items[2].SubItems.Add("Subitem 3") | Out-Null

# 订阅DrawColumnHeader事件
$listView1.add_DrawColumnHeader({
    param($sender, $e)
    $e.DrawDefault = $false

    # 绘制列头背景
    $e.Graphics.FillRectangle([System.Drawing.Brushes]::LightGray, $e.Bounds)
    $e.Graphics.DrawRectangle([System.Drawing.Pens]::Black, $e.Bounds)

    # 拆分Tag中的两行文本
    $lines = $e.Header.Tag -split "`n"
    $halfHeight = $e.Bounds.Height / 2

    # 创建RectangleF区域(显式转换避免重载歧义)
    $firstLineRect = New-Object System.Drawing.RectangleF(
        $e.Bounds.Left, $e.Bounds.Top, $e.Bounds.Width, $halfHeight
    )
    $secondLineRect = New-Object System.Drawing.RectangleF(
        $e.Bounds.Left, $e.Bounds.Top + $halfHeight, $e.Bounds.Width, $halfHeight
    )

    # 设置文本对齐方式
    $sf = New-Object System.Drawing.StringFormat
    $sf.LineAlignment = [System.Drawing.StringAlignment]::Center
    $sf.Alignment = [System.Drawing.StringAlignment]::Center

    # 绘制两行文本
    $e.Graphics.DrawString($lines[0], $listView1.Font, [System.Drawing.Brushes]::Black, $firstLineRect, $sf)
    $e.Graphics.DrawString($lines[1], $listView1.Font, [System.Drawing.Brushes]::Black, $secondLineRect, $sf)
})

$form.Controls.Add($listView1)
$form.ShowDialog() | Out-Null

关键修复点

  • 使用RectangleF替代Rectangle,显式匹配正确的DrawString重载,解决类型转换错误
  • 为列头设置Width属性,确保列可见
  • 补充绘制列头的背景和边框,提升视觉效果
  • 从Tag属性中拆分两行文本,实现动态内容支持

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 16:52:29