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时无报错,但列无法显示
错误原因
- PowerShell在解析.NET方法重载时存在歧义,将
Rectangle实例错误匹配到需要PointF的重载,导致类型转换失败 - 原代码未设置列头宽度,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
相关产品推荐
相关产品推荐

