.netpowershellwinformshyperlinklinklabel

Using Powershell to create click events for a System.Windows.Forms.Linklabel with multiple links


First time asking a question here. I'm working on designing a dynamic popup script to be used by other people.

One of the needs for this script is to have a popup that allows an everyday tech to create a message that has multiple links.

To do this, I've been trying to create a form with a single linklabel that has multiple links added to Linklabel.Links

The problem I've encountered is that while I can get a hyperlink to work when the user clicks on the label, I can't get powershell to differentiate between which hyper was clicked by the user.

Below is a snippet of my code. I have built custom tags to identify when the user want's to create a hyperlink

Add-Type -AssemblyName System.Windows.Forms

#....

# User's custom popup message. 
# Original script sorts through this information to identify where the hyper links should be.
$testLink = 'test <hlink-start><text-start>Click Here<text-end>http://www.google.com<hlink-end> Words Words <hlink-start>https://www.vmware.com<hlink-end> done'

# Stores the linklabel text after the tags in $testLink have been sorted through
$NewLabelText = ""

# Custom object that stores the url of each hyperlink; the startPosition; and the Length of text for the url
$URLinfo = New-Object -TypeName PSObject

#... Skipping code that sorts through $testLink 
#... Outcome is the following:
#... 
#... $NewLabelText =
#... 'test Click Here Words Words https://www.vmware.com done'
#... 
#... $URLinfo =
#... URL                    StartPos LinkLength
#... ---                    -------- ----------
#... http://www.google.com         5         10
#... https://www.vmware.com       28         22

# creates a test windows form
$form = New-Object System.Windows.Forms.Form

# Form title
$form.Text = "sample"

# Create new LinkLabel
$linklabel = New-Object System.Windows.Forms.LinkLabel

# Set LinkLabel text
$linklabel.Text = $NewLabelText

# Defines text that should be a hyperlink
foreach ($URL in $URLinfo)
{
    $linklabel.Links.Add($URL.StartPos, $URL.LinkLength, $URL.URL)
    
    # Attempted to navigate to defined Web page when Specific link is click.
    # Errors out. Add_Click is not a method of Links.
    #$linklabel.Links.add_Click({[system.Diagnostics.Process]::start($URL.URL)})
    

}

# Customizing linklable size
$linklabel.AutoSize = $true

# Add linklabel to form
$form.Controls.Add($linklabel)

# Customizing form size
$form.AutoSize = $true

# The add_click method here works. 
# Makes the entire Linklabel clickable including the non-highlighted parts
#$linklabel.add_Click({[system.Diagnostics.Process]::start($URLinfo[0].URL)})

# Shows form
$form.ShowDialog()

The below Microsoft documents show a method that allows for users to have multiple hyperlinks in a single linklabel, however this appears to use event handlers and is specifically for C#. Not sure if I can translate the solution to Powershell.

https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.linklabel.link?view=windowsdesktop-6.0

I also found an interesting solution using XML, but I don't know enough about xml to modify the code found here.

https://github.com/kunaludapi/Powershell/blob/master/Powershell%20WPF%20linklabel%20Hyperlink%20Demo.ps1


Solution

  • When you use a PowerShell script block { ... }) as an event delegate, you can formally declare the arguments that .NET passes to the delegate as parameters, using a param(...) block.

    Here, you want to subscribe to the link label's LinkClicked event, which expects a LinkLabelLinkClickedEventHandler delegate, whose event-arguments object contains the originating link in its .Link property, whose .LinkData property contains the target URL:

    $linklabel.add_LinkClicked({
      param($evtSender, $evtArgs)
      # Launch the default browser with the target URL.
      Start-Process $evtArgs.Link.LinkData
    })    
    

    Note the use of Start-Process for opening the URL as the PowerShell-native alternative to using the underlying .NET API, [System.Diagnostics.Process]::start().

    Note:


    Here's a self-contained sample (PS v5+) based on a streamlined version of your code:

    using namespace System.Windows.Forms
    Add-Type -AssemblyName System.Windows.Forms
    
    $form = [Form] @{ Text = 'sample' }
    
    $linklabel = [LinkLabel] @{
        Text     = 'Link 1: example.org; link 2: google.com'
        AutoSize = $true
    }
    
    # Sample hyperlinks to add to the text of the link label control.
    $URLInfo = @'
    StartPos,LinkLength,Url
    7,11,http://example.org
    29,10,https://google.com
    '@ | ConvertFrom-Csv
    
    # Add them.
    foreach ($URL in $URLinfo) {
        $null = $linklabel.Links.Add($URL.StartPos, $URL.LinkLength, $URL.URL)
    }
    
    # Register a handler for when the user clicks a link.
    $linklabel.add_LinkClicked({
            param($evtSender, $evtArgs)
            # Launch the default browser with the target URL.
            Start-Process $evtArgs.Link.LinkData
        })   
    
    $form.Controls.Add($linklabel)
    
    $null = $form.ShowDialog()