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

Time:08-24

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://docs.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 WPF linklabel Hyperlink Demo.ps1

CodePudding user response:

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:

  • For brevity, the parameter declarations above are untyped, but you may type them, which can provide IntelliSense when developing in Visual Studio Code with the PowerShell extension, for instance. See the docs for details on parameter declarations.

  • See this answer for a detailed discussion of using script blocks as event handlers, including an explanation of why .add_<eventName>() must be used in PowerShell to register for an event.


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()

CodePudding user response:

Thanks for all your answers! I actually was able to figure it out for those wondering. See below:

$form = New-Object System.Windows.Forms.Form

$form.Text = "sample"

$linklabel = New-Object System.Windows.Forms.LinkLabel

$linklabel.Text = $NewLabelText

#$linkLabel.LinkClicked  = [System.Windows.Forms.LinkLabelLinkClickedEventHandler]$linkLabel_LinkClicked

foreach ($URL in $URLinfo)
{
    $linklabel.Links.Add($URL.StartPos, $URL.LinkLength, $URL.URL)
    
    #$linklabel.Links.add_Click({[system.Diagnostics.Process]::start($URL.URL)})
    

}



$linklabel.AutoSize = $true

$form.Controls.Add($linklabel)

$form.AutoSize = $true

$linkLabel_LinkClicked = 
[System.Windows.Forms.LinkLabelLinkClickedEventHandler]{    
    param(
        [object]$sender, 
        [System.Windows.Forms.LinkLabelLinkClickedEventArgs]$e
    )

    Write-Host $e.link
    Write-Host $sender.links[0].LinkData
    
    $sender.Links[$sender.Links.IndexOf($e.Link)].Visited = $true;

    # Display the appropriate link based on the value of the 
    # LinkData property of the Link object.
    $target = $e.Link.LinkData

    [system.Diagnostics.Process]::start($target)
}

$linkLabel.add_LinkClicked($linkLabel_LinkClicked)


$form.ShowDialog()
  • Related