Adding text to a listbox

Ask questions about creating Graphical User Interfaces (GUI) in PowerShell and using WinForms controls.
Forum rules
Do not post any licensing information in this forum.

Any code longer than three lines should be added as code using the 'Select Code' dropdown menu or attached as a file.
User avatar
nai0248
Posts: 14
Joined: Tue Nov 16, 2010 2:29 am

Adding text to a listbox

Post by nai0248 » Thu Apr 19, 2018 8:52 am

I'm new to the GUI designer and attempting to use a Wizard tabbed form. The first tab is informational only, the second tab to select a collection of files and folders, and third tab takes data from the file in tab two to populate two listboxes. If the input file is an xml ([xml]...Get-Content, only one listbox is populated (Mission Partner Name). The Select Platform is not populated. If the input file is a text (CSV) file (Import-CSV), both listboxes are populated but all the values are include: @{Target=}. if the value is book it appears as @{Target=book}. I'm also a little new to PowerShell as well. Code attached and below...
Not sure why xml is not populating listbox and why csv is including additional characters.

Code: Select all

Function Get-FileName($Title, $FormType, $FileType)
{
	[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |
	Out-Null
	switch ($FormType)
	{
		'OpenFileDialog' {
			$OpenFileDialog = New-Object System.Windows.Forms.$FormType
			$OpenFileDialog.title = $Title
			$OpenFileDialog.RestoreDirectory = $true
			$OpenFileDialog.initialDirectory = $pwd #$initialDirectory
			$OpenFileDialog.filter = $FileType
			$OpenFileDialog.ShowHelp = $true
			$file = $OpenFileDialog.ShowDialog((New-Object System.Windows.Forms.Form -Property @{ TopMost = $true }))
			[int]$x = 0
			[int]$i = 0
			
			If ($file -eq "OK")
			{
				$OpenFileDialog.filename
			}
			Else
			{
				Write-Host "Operation cancelled by user" -ForegroundColor Red -BackgroundColor White
				Exit
			}
		}
		'FolderBrowserDialog' {
			$OpenFileDialog = New-Object System.Windows.Forms.$FormType
			$OpenFileDialog.Description = $Title
			$OpenFileDialog.ShowNewFolderButton = 'False'
			$OpenFileDialog.RootFolder = 'MyComputer'
			$file = $OpenFileDialog.ShowDialog((New-Object System.Windows.Forms.Form -Property @{ TopMost = $true }))
			[int]$x = 0
			[int]$i = 0
			
			If ($file -eq "OK")
			{
				$OpenFileDialog.SelectedPath
			}
			Else
			{
				Write-Host "Operation cancelled by user" -ForegroundColor Red -BackgroundColor White
				Exit
			}
		}
		default
		{
			Exit
		}
	}
	
	
} #end function Get-FileName

#-------------------------------------------------------
# NOTE: When new TabPage added place the validation code
# 		in the Validate-WizardPage function.
#-------------------------------------------------------
function Validate-WizardPage
{
<#
	Add TabPages and place the validation code in this function
#>
	[OutputType([boolean])]
	param([System.Windows.Forms.TabPage]$tabPage)
	
	if($tabPage -eq $tabpageStep1)
	{
		#TODO: Enter Validation Code here for Step 1
		if(-not $labelIntent.Text)
		{
			return $false	
		}
		
		return $true
	}
	elseif ($tabPage -eq $tabpageStep2)
	{
		#TODO: Enter Validation Code here for Step 2
		# if ((Test-Path $textbox1.Text -PathType Leaf) -and (Test-Path $textbox2.Text -PathType Container) -and (Test-Path $textbox3.Text -PathType Container))
		if ($textbox1.Text -and $textbox2.Text -and $textbox3.Text)
		{
			return $true
		}
		
		return $false
	}
	elseif ($tabPage -eq $tabpageStep3)
	{
		#TODO: Enter Validation Code here for Step 3
		if(	$radiobuttonSCAP.Checked -or
			$radiobuttonManual.Checked)
		{
			return $true
		}
	}
	#Add more pages here
	
	return $false
}



$buttonFinish_Click={
	#-------------------------------------------------------
	# TODO: Place finalization script here
	#-------------------------------------------------------
	
}

#region Events and Functions
$formESPSToSTIGACASUtilit_Load={
	Update-NavButtons
}

function Update-NavButtons
{
	<# 
		.DESCRIPTION
		Validates the current tab and Updates the Next, Prev and Finish buttons.
	#>
	$enabled = Validate-WizardPage $tabcontrolWizard.SelectedTab
	$buttonNext.Enabled = $enabled -and ($tabcontrolWizard.SelectedIndex -lt $tabcontrolWizard.TabCount - 1)
	$buttonBack.Enabled = $tabcontrolWizard.SelectedIndex -gt 0
	$buttonFinish.Enabled = $enabled -and ($tabcontrolWizard.SelectedIndex -eq $tabcontrolWizard.TabCount - 1)	
	#Uncomment to Hide Buttons
	#$buttonNext.Visible = ($tabcontrolWizard.SelectedIndex -lt $tabcontrolWizard.TabCount - 1)
	#$buttonFinish.Visible = ($tabcontrolWizard.SelectedIndex -eq $tabcontrolWizard.TabCount - 1)
}

$script:DeselectedIndex = -1
$tabcontrolWizard_Deselecting=[System.Windows.Forms.TabControlCancelEventHandler]{
#Event Argument: $_ = [System.Windows.Forms.TabControlCancelEventArgs]
	# Store the previous tab index
	$script:DeselectedIndex = $_.TabPageIndex
}

$tabcontrolWizard_Selecting=[System.Windows.Forms.TabControlCancelEventHandler]{
#Event Argument: $_ = [System.Windows.Forms.TabControlCancelEventArgs]
	# We only validate if we are moving to the Next TabPage. 
	# Users can move back without validating
	if($script:DeselectedIndex -ne -1 -and $script:DeselectedIndex -lt $_.TabPageIndex)
	{
		#Validate each page until we reach the one we want
		for($index = $script:DeselectedIndex; $index -lt $_.TabPageIndex; $index++)
		{
			$_.Cancel = -not (Validate-WizardPage $tabcontrolWizard.TabPages[$index])
			
			if($_.Cancel) 
			{
				# Cancel and Return if validation failed.
				return;
			}
		}
	}
	
	Update-NavButtons
}

$buttonBack_Click={
	#Go to the previous tab page
	if($tabcontrolWizard.SelectedIndex -gt 0)
	{
		$tabcontrolWizard.SelectedIndex--
	}
}

$buttonNext_Click={	
	#Go to the next tab page
	if($tabcontrolWizard.SelectedIndex -lt $tabcontrolWizard.TabCount - 1)
	{
		$tabcontrolWizard.SelectedIndex++
	}
}

#endregion


function Load-ListBox 
{
<#
	.SYNOPSIS
		This functions helps you load items into a ListBox or CheckedListBox.
	.DESCRIPTION
		Use this function to dynamically load items into the ListBox control.
	.PARAMETER  ListBox
		The ListBox control you want to add items to.
	.PARAMETER  Items
		The object or objects you wish to load into the ListBox's Items collection.
	.PARAMETER  DisplayMember
		Indicates the property to display for the items in this control.
	.PARAMETER  SelectionMode
		Allows multi-selection of items in the ListBox.
	.PARAMETER  Append
		Adds the item(s) to the ListBox without clearing the Items collection.
	.EXAMPLE
		Load-ListBox $ListBox1 "Red", "White", "Blue"
	.EXAMPLE
		Load-ListBox $listBox1 "Red" -Append
		Load-ListBox $listBox1 "White" -Append
		Load-ListBox $listBox1 "Blue" -Append
	.EXAMPLE
		Load-ListBox $listBox1 (Get-Process) "ProcessName"
#>
	Param (
		[ValidateNotNull()]
		[Parameter(Mandatory=$true)]
		[System.Windows.Forms.ListBox]$ListBox,
		[ValidateNotNull()]
		[Parameter(Mandatory=$true)]
		$Items,
	    [Parameter(Mandatory=$false)]
		[string]$DisplayMember,
		[switch]$SelectionMode,
		[switch]$Append
	)
	
	If ($SelectionMode)
	{
		$ListBox.SelectionMode = 'MultiExtended'
	}
	
	if(-not $Append)
	{
		$listBox.Items.Clear()	
	}
	
	if($Items -is [System.Windows.Forms.ListBox+ObjectCollection] -or $Items -is [System.Collections.ICollection])
	{
		$listBox.Items.AddRange($Items)
	}
	elseif ($Items -is [System.Collections.IEnumerable])
	{
		$listBox.BeginUpdate()
		foreach($obj in $Items)
		{
			$listBox.Items.Add($obj)
		}
		$listBox.EndUpdate()
	}
	else
	{
		$listBox.Items.Add($Items)	
	}
	
	$listBox.DisplayMember = $DisplayMember
	
	
}
#endregion

#------------------------------------------------------
# NOTE: When a Control State changes you should call
# 		Update-NavButtons to trigger validation
#------------------------------------------------------

$button1_Click = {
	#TODO: Place custom script here
	$textbox1.Text = Get-FileName -Title "Select ESPS File" -FormType "OpenFileDialog" -FileType "XML Data (*.xml)|*.xml|Comma delimited File (*.csv)|*.csv"
	$ESPSPath = [IO.Path]::GetDirectoryName($textbox1.Text)
	$ESPSFileExtension = [IO.Path]::GetExtension($textbox1.Text)
	
	If ($ESPSFileExtension -eq ".xml")
	{
		[xml]$ESPSDetails = Get-Content $textbox1.Text
		$Platforms = $ESPSDetails.ServerToolkitFindings.ServerToolkitFinding.target | Sort-Object | Get-Unique
		$MissionPartners = $ESPSDetails.ServerToolkitFindings.ServerToolkitFinding.MissionPartner | Sort-Object | Get-Unique
		
		#		Load-ListBox $listbox1 -Items $Platform
		#		Load-ListBox $listbox2 -Items $MissionPartner
		Foreach ($Platform in $Platforms) #Populate Listbox on 3rd tab
		{
			# [void]$listbox1.Items.Add($Platform)
			Load-ListBox $listbox1 $Platform -SelectionMode -Append
		}
		
		
		foreach ($MissionPartner in $MissionPartners)
		{
			# [void]$listbox2.Items.Add($MissionPartner)
			Load-ListBox $listbox2 $MissionPartner -Append
		}
	}
	Else
	{
		$ESPSDetails = Import-Csv $textbox1.Text
		$Platforms = $ESPSDetails | select Target | Sort Target -Unique
		$MissionPartners = $ESPSDetails | select MissionPartner | Sort MissionPartner -Unique
		
		#		Load-ListBox $listbox1 -Items $Platform
		#		Load-ListBox $listbox2 -Items $MissionPartner
		
		Foreach ($Platform in $Platforms) #Populate Listbox on 3rd tab
		{
			# [void]$listbox1.Items.Add($Platform)
			Load-ListBox $listbox1 $Platform -SelectionMode -Append
		}
		
		foreach ($MissionPartner in $MissionPartners)
		{
			# [void]$listbox2.Items.Add($MissionPartner)
			Load-ListBox $listbox2 $MissionPartner -Append
		}
	}
	Update-NavButtons
}

$button2_Click = {
	$textbox2.Text = Get-FileName -Title "Select folder of the source STIG files" -FormType "FolderBrowserDialog"
	Update-NavButtons
}

$button3_Click = {
	$textbox3.Text = Get-FileName -Title "Specify Folder for new STIG file(s)" -FormType "FolderBrowserDialog"
	Update-NavButtons
}

$textbox1_TextChanged={
	Update-NavButtons	
}

$textbox2_TextChanged = {
	Update-NavButtons	
}

$textbox3_TextChanged = {
	Update-NavButtons
}

$checkboxCheckToContinue_CheckedChanged = {
	Update-NavButtons
}

$radiobuttonOption_CheckedChanged = {
	
	if ($this.Checked)
	{
		Update-NavButtons
	}
}

$listbox1_SelectedIndexChanged = {
	Update-NavButtons
}

$listbox2_SelectedIndexChanged = {
	Update-NavButtons
}

$checkboxIncludeACASScanRepor_CheckedChanged = {
	Update-NavButtons
}

#region Control Helper Functions
Attachments
Wizard_Form.psf
(79.05 KiB) Downloaded 21 times
Last edited by nai0248 on Thu Apr 19, 2018 10:18 am, edited 1 time in total.

User avatar
jvierra
Posts: 12774
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Adding text to a listbox

Post by jvierra » Thu Apr 19, 2018 9:10 am

Hello nai0248

Without your files it would be very difficult to understand what the issue is. At a quick glance it appears that your XML extraction is incorrect. The selectin methods used will return nodes and not text and this cannot be displayed in a ListBox.

Create a simple form and just load the listbox to see the failure. Post the simple form and a copy of the XML if you cannot see the source of your issue.

User avatar
nai0248
Posts: 14
Joined: Tue Nov 16, 2010 2:29 am

Re: Adding text to a listbox

Post by nai0248 » Fri Apr 20, 2018 7:04 am

Updated, Sorry for the large file size.

Code: Select all


Function Get-FileName($Title, $FormType, $FileType)
{
	[System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms") |
	Out-Null
	switch ($FormType)
	{
		'OpenFileDialog' {
			$OpenFileDialog = New-Object System.Windows.Forms.$FormType
			$OpenFileDialog.title = $Title
			$OpenFileDialog.RestoreDirectory = $true
			$OpenFileDialog.initialDirectory = $pwd #$initialDirectory
			$OpenFileDialog.filter = $FileType
			$OpenFileDialog.ShowHelp = $true
			$file = $OpenFileDialog.ShowDialog((New-Object System.Windows.Forms.Form -Property @{ TopMost = $true }))
			[int]$x = 0
			[int]$i = 0
			
			If ($file -eq "OK")
			{
				$OpenFileDialog.filename
			}
			Else
			{
				Write-Host "Operation cancelled by user" -ForegroundColor Red -BackgroundColor White
				Exit
			}
		}
		'FolderBrowserDialog' {
			$OpenFileDialog = New-Object System.Windows.Forms.$FormType
			$OpenFileDialog.Description = $Title
			$OpenFileDialog.ShowNewFolderButton = 'False'
			$OpenFileDialog.RootFolder = 'MyComputer'
			$file = $OpenFileDialog.ShowDialog((New-Object System.Windows.Forms.Form -Property @{ TopMost = $true }))
			[int]$x = 0
			[int]$i = 0
			
			If ($file -eq "OK")
			{
				$OpenFileDialog.SelectedPath
			}
			Else
			{
				Write-Host "Operation cancelled by user" -ForegroundColor Red -BackgroundColor White
				Exit
			}
		}
		default
		{
			Exit
		}
	}
	
	
} #end function Get-FileName

$form1_Load={
	#TODO: Initialize Form Controls here
	
}

#region Control Helper Functions
function Load-ListBox
{
<#
	.SYNOPSIS
		This functions helps you load items into a ListBox or CheckedListBox.
	.DESCRIPTION
		Use this function to dynamically load items into the ListBox control.
	.PARAMETER  ListBox
		The ListBox control you want to add items to.
	.PARAMETER  Items
		The object or objects you wish to load into the ListBox's Items collection.
	.PARAMETER  DisplayMember
		Indicates the property to display for the items in this control.
	.PARAMETER  SelectionMode
		Allows multi-selection of items in the ListBox.
	.PARAMETER  Append
		Adds the item(s) to the ListBox without clearing the Items collection.
	.EXAMPLE
		Load-ListBox $ListBox1 "Red", "White", "Blue"
	.EXAMPLE
		Load-ListBox $listBox1 "Red" -Append
		Load-ListBox $listBox1 "White" -Append
		Load-ListBox $listBox1 "Blue" -Append
	.EXAMPLE
		Load-ListBox $listBox1 (Get-Process) "ProcessName"
#>
	Param (
		[ValidateNotNull()]
		[Parameter(Mandatory = $true)]
		[System.Windows.Forms.ListBox]$ListBox,
		[ValidateNotNull()]
		[Parameter(Mandatory = $true)]
		$Items,
		[Parameter(Mandatory = $false)]
		[string]$DisplayMember,
		[switch]$SelectionMode,
		[switch]$Append
	)
	
	If ($SelectionMode)
	{
		$ListBox.SelectionMode = 'MultiExtended'
	}
	
	if (-not $Append)
	{
		$listBox.Items.Clear()
	}
	
	if ($Items -is [System.Windows.Forms.ListBox+ObjectCollection] -or $Items -is [System.Collections.ICollection])
	{
		$listBox.Items.AddRange($Items)
	}
	elseif ($Items -is [System.Collections.IEnumerable])
	{
		$listBox.BeginUpdate()
		foreach ($obj in $Items)
		{
			$listBox.Items.Add($obj)
		}
		$listBox.EndUpdate()
	}
	else
	{
		$listBox.Items.Add($Items)
	}
	
	$listBox.DisplayMember = $DisplayMember
	
	
}
#endregion

$buttonLoadFile_Click = {
	$listBox1.Items.Clear()
	$listBox2.Items.Clear()
	$textbox1.Text = Get-FileName -Title "Select File" -FormType "OpenFileDialog" -FileType "XML Data (*.xml)|*.xml|Comma delimited File (*.csv)|*.csv"
	$ESPSPath = [IO.Path]::GetDirectoryName($textbox1.Text)
	$ESPSFileExtension = [IO.Path]::GetExtension($textbox1.Text)
	
	If ($ESPSFileExtension -eq ".xml")
	{
		[xml]$ESPSDetails = Get-Content $textbox1.Text
		$Platform = $ESPSDetails.ServerToolkitFindings.ServerToolkitFinding.target | Sort-Object | Get-Unique
		$MissionPartner = $ESPSDetails.ServerToolkitFindings.ServerToolkitFinding.MissionPartner | Sort-Object | Get-Unique
		
		Load-ListBox $listbox2 $Platform -SelectionMode
		Load-ListBox $listbox1 $MissionPartner
	}
	Else
	{
		$ESPSDetails = Import-Csv $textbox1.Text
		$Platforms = $ESPSDetails | select Target | Sort Target -Unique
		$MissionPartners = $ESPSDetails | select MissionPartner | Sort MissionPartner -Unique
		
		Load-ListBox $listbox2 $Platforms -SelectionMode
		foreach ($MissionPartner in $MissionPartners)
		{
			Load-ListBox $listbox1 $MissionPartner -Append
		}
	}
}

Attachments
Report.csv
(5.04 MiB) Downloaded 18 times
listbox_form.psf
(45.51 KiB) Downloaded 25 times
Result.xml
(5.6 MiB) Downloaded 18 times
Last edited by nai0248 on Fri Apr 20, 2018 8:05 am, edited 1 time in total.

User avatar
jvierra
Posts: 12774
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Adding text to a listbox

Post by jvierra » Fri Apr 20, 2018 7:28 am

The XML file loads into both ListBoxes. What is it that is supposed to happen? I still cannot quite understand what you are trying to do.

User avatar
nai0248
Posts: 14
Joined: Tue Nov 16, 2010 2:29 am

Re: Adding text to a listbox

Post by nai0248 » Fri Apr 20, 2018 11:26 am

I was able to figure out the issue. Essentially with Import-CSV and populating the list box, the header from the field was getting included with each data entry with the format @{headername=data}. I first tried to eliminate the Header using

Code: Select all

FT -HideTableHeaders
but that gave me a bunch of...

Microsoft.PowerShell.Commands.Internal.Format.FormatStartData
Microsoft.PowerShell.Commands.Internal.Format.GroupStartData

To fix this issue I added to my select statement; select fieldname -ExpandProperty feildname
Now only the intended data is populated in the list box.

User avatar
jvierra
Posts: 12774
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Adding text to a listbox

Post by jvierra » Fri Apr 20, 2018 11:42 am

I thought it was the XML that was an issue?

User avatar
jvierra
Posts: 12774
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Adding text to a listbox

Post by jvierra » Fri Apr 20, 2018 12:01 pm

The following code makes no sense. It loads the same thing into both list boxes incorrectly.

Code: Select all

	Else
	{
		$ESPSDetails = Import-Csv $textbox1.Text
		$Platforms = $ESPSDetails | select Target | Sort Target -Unique
		$MissionPartners = $ESPSDetails | select MissionPartner | Sort MissionPartner -Unique
		
		Load-ListBox $listbox2 $Platforms -SelectionMode
		foreach ($MissionPartner in $MissionPartners)
		{
			Load-ListBox $listbox1 $MissionPartner -Append
		}
Here is how to do what it appears you are trying to do. Notice how I changed the code.

Code: Select all

    }else{
        $ESPSDetails = Import-Csv $textbox1.Text | select target,MissionPartner

        $partners = $ESPSDetails | sort MissionPartner -Unique
        Load-ListBox $listbox1 $partners -DisplayMember MissionPartner

        $target = $ESPSDetails | sort Target -Unique
        Load-ListBox $listbox2 $target -DisplayMember Target
    }
If you really want a relational view thenyou have to filter the two first by the related field.

User avatar
jvierra
Posts: 12774
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Adding text to a listbox

Post by jvierra » Fri Apr 20, 2018 12:04 pm

Relational filtering:

$systemtarget = $ESPSDetails | where{$_.MissionPartner -eq 'System2' }| select target -unique

User avatar
jvierra
Posts: 12774
Joined: Tue May 22, 2007 9:57 am
Contact:

Re: Adding text to a listbox

Post by jvierra » Fri Apr 20, 2018 12:04 pm

If you load the CSV to a DataTable the sort and relation can be defined and the lists will be automatic.

User avatar
Jesssmart
Posts: 1
Joined: Tue Jun 16, 2015 3:10 am
Contact:

Re: Adding text to a listbox

Post by Jesssmart » Wed May 16, 2018 3:10 am

The best аnd easiest wаy to do this is to use a dataset and filter the dataview as the text is filled in. This will keep all data and allow the filter to just adjust the visible items..

Locked