How to change height of items in ListBox in powershell? - winforms

I'm trying to set the height of items to be equal to the height of ListBox. In other words, only one item must be visible in ListBox. Right now, two items are visible.
Add-Type -AssemblyName System.Windows.Forms
[Windows.Forms.Application]::EnableVisualStyles()
# $OwnerDrawVariable = [Windows.Forms.DrawMode]::OwnerDrawVariable
# $OwnerDrawFixed = [Windows.Forms.DrawMode]::OwnerDrawFixed
$form = New-Object Windows.Forms.Form
$form.ClientSize = '400,400'
$form.text = "Form"
$form.TopMost = $false
$listBox = New-Object Windows.Forms.ListBox
$listBox.text = "listBox"
$listBox.width = 80
$listBox.height = 30
$listBox.location = New-Object Drawing.Point(70,10)
# $listBox.IntegralHeight = $false
# $listBox.DrawMode = $OwnerDrawVariable
$listBox.ItemHeight = 30
#('1','2','3') | ForEach-Object {[void] $listBox.Items.Add($_)}
$form.controls.AddRange(#($listBox))
[void]$form.ShowDialog()
I've tried changing DrawMode property as well as IntegralHeight to no avail. Any advice?

As the value name indicates, [DrawMode]::OwnerDrawFixed requires the control owner (that's you!) to explicitly draw the items on screen.
You can do so by adding an event handler to the DrawItem event property:
$listBox.add_DrawItem({
param(
[object]$sender,
[System.Windows.Forms.DrawItemEventArgs]$eargs
)
$eargs.DrawBackground()
$eargs.Graphics.DrawString($listBox.Items[$eargs.Index].ToString(), $eargs.Font, [System.Drawing.Brushes]::Black, $eargs.Bounds.Left, $eargs.Bounds.Top)
$eargs.DrawFocusRectangle()
})
$eargs.Font is inherited from $listbox.Font, so modify that if you want the drawn strings to be larger as well:
$listBox.Font = [System.Drawing.Font]::new($listBox.Font.FontFamily.Name, 18)

Related

How Can I change the color of the Text on TabPage?

What properties need to be applied to change the forecolor and backcolor of the text on Tabpage?
See Picture:
https://imgur.com/a/Su8aSg7
Here is my Code:
$TabControl_Main = New-Object System.Windows.Forms.TabControl
$TabControl_Main.Location = New-Object System.Drawing.Size(20,550)
$TabControl_Main.Size = New-Object System.Drawing.Size(850,270)
$form_MainForm.Controls.Add($TabControl_Main)
$TabPage1 = New-Object System.Windows.Forms.TabPage
$TabPage1.Location = New-Object System.Drawing.Size(20,550)
$TabPage1.Size = New-Object System.Drawing.Size(850,270)
$TabPage1.Text = "Processes"
$TabControl_Main.Controls.Add($TabPage1)
You have to create an event and draw the area. Here is some code based on this example in c#, credits #Fun Mun Pieng.
# assign a color for each tab
$PageColor = #{0 = "lightgreen";
1 = "yellow";
2 = "lightblue"}
# define the event
$tabControl_Drawing = {
param([object]$Sender, [System.EventArgs]$e)
$Background = new-object Drawing.SolidBrush $PageColor[$e.Index]
$Foreground = new-object Drawing.SolidBrush black
$tabGraphics = $e.Graphics
$tabBounds = $e.Bounds
$tabGraphics.FillRectangle($Background,$tabBounds)
$tabTextSize = $tabGraphics.MeasureString($sender.TabPages[$e.Index].text, $e.Font)
$tabGraphics.DrawString($Sender.TabPages[$e.Index].Text,$e.Font,$Foreground,$tabBounds.Left + ($tabBounds.Width - $tabTextSize.Width) / 2,$tabBounds.Top + ($tabBounds.Height -$tabTextSize.Height) / 2 +1)
$e.DrawFocusRectangle()
}
# add the event
$TabControl_Main.add_DrawItem($tabControl_Drawing)
A little easier to use is HotTrack:
$TabControl_Main.HotTrack = $true
You will see the effect when you execute your script with powershell instead of powershell ISE.
BackColor does nothing. To use the words of MSDN:
BackColor > This member is not meaningful for this control.
edit: added the code.

How to limit number of lines in a TextBox and split the lines to strings?

How can I achieve that the input of the TextBox with multilines is only possible to a specific number of lines e.g. 10 lines only.
Further I want to get the input of each line and write each line to a separate variable to work later with this variables. It would be nice if the user gets a messagebox with warning that only 10 lines are possible.
Any help would be appreciated
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#Assembly PresentationFramework wird geladen
Add-Type -AssemblyName PresentationFramework
$form = New-Object System.Windows.Forms.Form
$form.StartPosition = 'CenterScreen' #Formstartposition Zentrum
$form.Size = New-Object System.Drawing.Size(500,400)
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.DataBindings.DefaultDataSourceUpdateMode = 0
$textBox.Location = New-Object System.Drawing.Point((110),(90))
$textBox.Size = New-Object System.Drawing.Size(288,150)
$textBox.TabIndex = 0
$textBox.Multiline =$true
$form.Controls.Add($textBox)
$form.ShowDialog() | Out-Null
1.Get Line count on the event of TextChanged.
2.Turn the iList into a ArrayList.
3.Get the difference from max line to current line count.
4.Remove the range from the ArrayList.
5.Set the content of the Textbox to the Arraylist
6.Set the curser to end of textbox.
$TextboxMaxLines = 10
$textBox.Add_TextChanged({
If($textBox.Lines.Count -gt $TextboxMaxLines){
[System.Collections.ArrayList]$AL = $textBox.Lines
[int]$LC = ($textBox.Lines.Count - $TextboxMaxLines)
$Al.RemoveRange($TextboxMaxLines, $LC)
$textbox.Lines = $AL
$textbox.SelectionStart = ($textbox.Text.Length)
$textbox.SelectionLength = 0
}
})

Listbox Bound to a PSObject list DisplayMember not working

I have a form with a listbox on it. In this listbox I want to put PSObjects that have these members: Name, Location, ID.
I have created a variable: $list that holds all the PSObjects and I want to bind $list to the $listbox so that anytime $list is modified the $listbox automatically updates.
I am able to bind $list to the $listbox but it doesn't display it properly. I would like only the name member to be visible. The problem is, regardless of if I set the DisplayMember property or not, the $list is still displayed like this:
_______________________________________
|#{Name=Jim; Location=Somewhere; ID=0}|
|#{Name=Sam; Location=Somewhere; ID=1}|
|_____________________________________|
I want it to look like this:
______
|Jim |
|Sam |
|____|
Here's the relevant code I'm working with:
#####PSObject Initialization Code:##########
$obj1 = New-Object -TypeName PSObject -Property #{
'Name' = 'Jim';'Location' = 'Somewhere';'ID' = 0
};$obj2 = New-Object -TypeName PSObject -Property #{
'Name' = 'Sam';'Location' = 'Somewhere';'ID' = 1
};$list = $obj1,$obj2
#####Listbox Code:##########################
$listbox = New-Object System.Windows.Forms.ListBox
$listbox.Dock = 'Fill'
$listbox.SelectionMode = 'MultiExtended'
$listbox.DisplayMember = 'Name'
$listbox.DataSource = $list
#####Form Code##############################
[void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)
[void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Drawing”)
$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(500,500)
$form.Controls.Add($listbox); $form.ShowDialog()
Does anyone have an idea about why the DisplayMember property is seemingly overlooked when I bind the list and how to get the display into the desired format?
Note: If the PSObjects are added from the list one at a time, then it displays properly, but this gets clunky in my application.
Figured I would post this even if it's old, a bunch of folk have looked
The trick was to cast the array as an arraylist:
$listbox.DataSource = [system.collections.arraylist]$itemList

In PowerShell and Windows Forms, how to capture user-entered data using multiple dynamically created input controls

I have a script I need to use for multiple parameter data collection, as follows:
function Build-FormPanel($FormTitle){
Add-Type -Assembly System.Windows.Forms ## Load the Windows Forms assembly
## Create the main form
$form = New-Object Windows.Forms.Form
$form.FormBorderStyle = "FixedToolWindow"
$form.Text = $FormTitle
$form.AutoScroll = $True
$form.StartPosition = "CenterScreen"
$form.Width = 740 ; $form.Height = 480 # Make the form wider
#Add Buttons- ## Create the button panel to hold the OK and Cancel buttons
$buttonPanel = New-Object Windows.Forms.Panel
$buttonPanel.Size = New-Object Drawing.Size #(400,40)
$buttonPanel.Dock = "Bottom"
$cancelButton = New-Object Windows.Forms.Button
$cancelButton.Top = $buttonPanel.Height - $cancelButton.Height - 10; $cancelButton.Left = $buttonPanel.Width - $cancelButton.Width - 10
$cancelButton.Text = "Cancel"
$cancelButton.DialogResult = "Cancel"
$cancelButton.Anchor = "Right"
## Create the OK button, which will anchor to the left of Cancel
$okButton = New-Object Windows.Forms.Button
$okButton.Top = $cancelButton.Top ; $okButton.Left = $cancelButton.Left - $okButton.Width - 5
$okButton.Text = "Ok"
$okButton.DialogResult = "Ok"
$okButton.Anchor = "Right"
## Add the buttons to the button panel
$buttonPanel.Controls.Add($okButton)
$buttonPanel.Controls.Add($cancelButton)
## Add the button panel to the form
$form.Controls.Add($buttonPanel)
## Set Default actions for the buttons
$form.AcceptButton = $okButton # ENTER = Ok
$form.CancelButton = $cancelButton # ESCAPE = Cancel
return $form
}
$LeftMargin = 25
$BottomMargin = 30
$i = 0
$form = Build-FormPanel "Please update server configurations"
foreach($param in $hash){#Where $hash is an "dictionary" of key/value pairs
$k = $param.Key
$v = $param.Value
$lblValue = New-Object System.Windows.Forms.Label
$lblValue.Text = $k+":"
$lblValue.Top = 20*$i ; $lblValue.Left = $LeftMargin; $lblValue.Width=150 ;$lblValue.AutoSize = $true
$form.Controls.Add($lblValue) # Add to Form
#
$txtValue = New-Object Windows.Forms.TextBox
$txtValue.Top = 20*$i; $txtValue.Left = 160; $txtValue.Width = 320;
$txtValue.Text = $v
$form.Controls.Add($txtValue) # Add to Form
$i++
}
$form.Topmost = $True
$form.Add_Shown( { $form.Activate(); } )
$result = $form.ShowDialog()
if($result -eq "OK")
{
$j = 0;
foreach($param in $hash){
${"txtValue_$j"}.Text
$j++
}
}
else {Write-Host "Cancel"}
Basically, this works OK to display the form and inputs. But after submission, I am unable to capture all the user inputs. Only the last input value is captured, obviously because the variables get overwritten in the loop.
How can I achieve capturing the data as described?
The issue as you have mentioned is because of the its getting overwritten.
I can give you a logical set off.
YOu can use it in a loop and in the loop , you store all the data either in array or if its dynamic then you can use arraylist by using
New-Object System.Collections.ArrayList
. But recommended is to create PSCustomObject , store in that and add that to the arraylist each time.
Finally you can get the output captured in the arraylist.
Further you can try making the arraylist Global so that it will be available for the entire script.
Hope it helps.

Powershell: Selecting DataGridView Row

So far I have this code.
$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(900,600)
$dataGridView = New-Object System.Windows.Forms.DataGridView
$dataGridView.Size=New-Object System.Drawing.Size(800,400)
$go = New-Object System.Windows.Forms.Button
$go.Location = New-Object System.Drawing.Size(300,450)
$go.Size = New-Object System.Drawing.Size(75,23)
$go.text = "Select"
$form.Controls.Add($go)
$form.Controls.Add($dataGridView)
$dataGridView.ColumnCount = 4
$dataGridView.ColumnHeadersVisible = $true
$dataGridView.Columns[0].Name = "Name"
$dataGridView.Columns[1].Name = "ID"
$dataGridView.Columns[2].Name = "Description"
$dataGridView.Columns[3].Name = "Memory"
$dataGridView.Columns[0].width = 240
get-process | foreach {
$dataGridView.Rows.Add($_.Name,$_.ID,$_.Description,$_.WorkingSet) | out-null
}
$go.Add_Click({
$selectedRow = $dataGridView.CurrentRowIndex
write-host $selectedRow
})
[void]$form.ShowDialog()
It simply gets the Process Name, ID, etc. properties and puts them into pre-defined headers in a DataGridView.
My problem is that I want to see the row I've clicked on via $selectedRow = $dataGridView.CurrentRowIndex and output it to the console. Instead, when the 'Select' button is pushed, a blank string is output to the terminal.
You can also get the row index with:
$dataGridView.CurrentCell.RowIndex
or
$dataGridView.SelectedRows[0].Index
You may also want to set the grid MultiSelect property to $false. Currently it allows multiple rows selection. Another thing to consider is setting the SelectionMode property to 'FullRowSelect'. When the grid is populated the first column is selected, not the whole row.
Change
$selectedRow = $dataGridView.CurrentRowIndex
to
$selectedRow = $dataGridView.CurrentRow.Index

Resources