How to use z-index for label in powershell using System.Windows.Forms

Viewed 440

I am trying to overlap a System.Windows.Forms.Label to over another Label in a Powershell script. Till now i have not found any working solution in- or outside Stackoverflow. Also the solution in this thread using transparancy does not work for me.

What i want to accomplish can be best demonstrated by the Powershell script below. A dot should be placed on top the 'Hi Mum!' label. Currenly the dot is partially overlayed by the 'Hi Mum!` label, though the dot has been brought to the front.

Add-Type -AssemblyName System.Windows.Forms

$FONT_WINGD = [System.Drawing.Font]::new("Microsoft Wingdings", 18)
$FONT_LARGE_BOLD = [System.Drawing.Font]::new("Microsoft Sans Serif", 18, [System.Drawing.FontStyle]::Bold)

$MyForm                     = New-Object System.Windows.Forms.Form
$MyForm.BackColor           = [System.Drawing.Color]::FromArgb(200,20, 20)


$MyLabel                    = New-Object system.Windows.Forms.Label
$MyLabel.Text               = "HI Mum !" 
$MyLabel.Font               = $FONT_LARGE_BOLD
$MyLabel.width              = 150
$MyLabel.height             = 24
$MyLabel.location           = New-Object System.Drawing.Point(40,20)
#$MyLabel.BackColor             = [System.Drawing.Color]::FromName("Transparent")
$MyLabel.BackColor          = [System.Drawing.Color]::FromName("Green")
$MyLabel.SendToBack()

$Dot                        = New-Object system.Windows.Forms.Label
$Dot.text                   = [System.Char]::ConvertFromUtf32(0x25CF);
$Dot.ForeColor              = [System.Drawing.Color]::FromArgb(155, 0, 79)
#$Dot.BackColor             = [System.Drawing.Color]::FromName("Transparent")
$Dot.BackColor          = [System.Drawing.Color]::FromName("Blue")
$Dot.width                  = 15
$Dot.height                 = 15
$Dot.location               = New-Object System.Drawing.Point(56,4)
$Dot.Font                   = $FONT_WINGD
$Dot.BringToFront()


$MyForm.controls.AddRange(@($MyLabel,$Dot))

$MyForm.ShowDialog()

enter image description here

2 Answers

Once you've added the control to a parent, use the Controls property on the parent to set the "child index" (the z-index):

# ...
$MyForm.Controls.AddRange(@($MyLabel,$Dot))

$MyForm.Controls.SetChildIndex($MyLabel, 2)
$Dot.Controls.SetChildIndex($Dot, 1)

You could create a simple function to resolve the parent and set the index like so:

function Set-WinFormControlZIndex
{
  param(
    [Parameter(Mandatory)]
    [System.Windows.Forms.Control]$Control,

    [int]$Index = -1
  )

  if($Control.Parent -is [System.Windows.Forms.Control]){
    $Control.Parent.Controls.SetChildIndex($Control, $Index)
  }
}

Then use like this:

# ...
$MyForm.Controls.AddRange(@($MyLabel,$Dot))

Set-WinFormControlZIndex $Dot 1
Set-WinFormControlZIndex $MyLabel 2

For me (also PowerShell 5.1) this works:

move $MyLabel.SendToBack() and $Dot.BringToFront() AFTER adding these controls to the form:

$MyForm.Controls.AddRange(@($MyLabel,$Dot))
$MyLabel.SendToBack()
$Dot.BringToFront()

OR

Remove $MyLabel.SendToBack() and $Dot.BringToFront() from your code and do

$MyForm.Controls.AddRange(@($MyLabel,$Dot))
$MyForm.Controls.SetChildIndex($Dot, 1)
$MyForm.Controls.SetChildIndex($MyLabel, 2)

The above works, but what the code is missing is to set the .TextAlign property on the label that holds the dot. Because of that, the dot is actually cut off in that small label size.

Either set $Dot.Width and $Dot.Height to larger pixel sizes so the dot will actually fit, or do

$Dot.TextAlign = 'MiddleCenter'
# and after adding to the Forms Control collection, 
$MyForm.Controls.AddRange(@($MyLabel,$Dot))
$Dot.BringToFront()

(To make the picture clearer, I have set the dot character to be yellow and set the .Location to (58,8))

enter image description here

Related