I need a listview that can support a Column header with two lines of text. I have spent a lot of time trying to use add_DrawColumnHeader to create that 2nd line. I have no issues creating it in c# but powershell seems to be elusive.
when loading the e.Graphics.Drawstring with the Rectangle I get this error:
Cannot convert argument "point", with value: "{X=60,Y=8,Width=60,Height=8}", for "DrawString" to type "System.Drawing.PointF"
When I check to see if the Overload is available, I see this, so it should work:
OverloadDefinitions
-------------------
void DrawString(string s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y)
void DrawString(string s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle)
void DrawString(string s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.RectangleF layoutRectangle, System.Drawing.StringFormat format)
void DrawString(string s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point)
void DrawString(string s, System.Drawing.Font font, System.Drawing.Brush brush, float x, float y, System.Drawing.StringFormat format)
void DrawString(string s, System.Drawing.Font font, System.Drawing.Brush brush, System.Drawing.PointF point, System.Drawing.StringFormat format)
If I use the Visual Studio Powershell Form I don't get a error, but I don't get columns either.. LOL
This is a simplified example of my code:
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
# Add columns
$columnHeader1 = New-Object System.Windows.Forms.ColumnHeader
$columnHeader1.Tag = "First Line`nSecond Line"
$columnHeader2 = New-Object System.Windows.Forms.ColumnHeader
$columnHeader2.Tag = "Third Line`nFourth Line"
$listView1.Columns.AddRange(@($columnHeader1, $columnHeader2))
# Add items for demonstration
$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
# Subscribe to the DrawColumnHeader event
$listView1.add_DrawColumnHeader({
param($sender, $e)
$e.DrawDefault = $false
$Global:ee = $e
# Draw two rows of text
$sf = New-Object System.Drawing.StringFormat
$sf.LineAlignment = [System.Drawing.StringAlignment]::Center
$sf.Alignment = [System.Drawing.StringAlignment]::Center
$HalfHeight = $e.Bounds.Height / 2
$TopHeightHalf = $e.Bounds.Top + $e.Bounds.Height / 2
$firstLineRect = New-Object System.Drawing.Rectangle ($e.Bounds.Left, $e.Bounds.Top, $e.Bounds.Width, $e.Bounds.Height / 2)
$secondLineRect = New-Object System.Drawing.Rectangle ($e.Bounds.Left,$e.Bounds.Top + $e.Bounds.Height / 2 , $e.Bounds.Width, $HalfHeight)
$e.Graphics.DrawString("First Line", $listView1.Font, [System.Drawing.Brushes]::Black, $firstLineRect, $sf)
$e.Graphics.DrawString("Second Line", $listView1.Font, [System.Drawing.Brushes]::Black, $secondLineRect, $sf)
})
# Add ListView control to the form
$form.Controls.Add($listView1)
# Show the form
$form.ShowDialog() | Out-Null
Short Answer
You're missing an
F- change:to
Long Answer
This appears to be caused by a difference in the way PowerShell does type coercion versus C# - your code is passing parameters to
DrawStringwith the following types:There's no exact match for these parameters though - the overloads of
DrawStringare:The C# compiler realises
System.Drawing.SolidBrushinherits fromSystem.Drawing.Brush, and it also finds the implicit conversion operator forRectangleF.Implicit(Rectangle to RectangleF)and it uses this to invoke the following overload:PowerShell, on the other hand, seems to be trying to bind to this overload of
DrawStringfor... reasons (basically it's not 100% identical to C#):and the error is saying it can't convert
$firstLineRect(aSystem.Drawing.Rectangle) to aSystem.Drawing.PointFfor thepointparameter.If you explicitly assign a
System.Drawing.RectangleFto$firstLineRectPowerShell will select the same overload as C# and you're golden...... but don't forget to specifically assign a
System.Drawing.RectangleF(with theFagain) to$secondLineRectas well otherwise you're back to square one...Update
You could also explicitly cast to
System.Drawing.Rectangleand PowerShell will invoke the appropriate conversion operator fine:but it seems it doesn't consider the implicit conversion operator during overload selection :-(
To use this in your code: