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

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

Related

Powershell timer : no action is launched

I want my timer to consult a file (consigne.csv) and display the "consigne" column according to the date I defined.
The data of this file would be regularly modified, hence the choice of the timer.
The form opens with the correct information but the information is not updated.
Thanks for your help.
Script :
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[System.Windows.Forms.Application]::EnableVisualStyles();
################ TIMER ##################################
$Timer = new-object System.Windows.forms.timer
$Timer.Interval = 1000
#Action.
$Timer.Add_Tick({
#Interval after boot.
$Timer.Interval = (5000)
#Command
$global:today = get-date -format "dd/MM/yy"
$global:DesktopPath = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::Desktop)
$global:TxtConsigne= (import-csv "$DesktopPath\consigne.csv" -encoding UTF8 -delimiter ";")
$global:Message = ($TxtConsigne | where-object {$_.EXPIRATION -ge $today})
})
################ Form #####################################
#Form
$Form = New-Object System.Windows.Forms.Form
$Form.Location = New-Object System.Drawing.Point 0,570
$Form.Size = New-Object System.Drawing.Size(1920,260)
# Consigne
$Consigne = New-Object system.windows.Forms.Label
$Consigne.Location = New-Object System.Drawing.Point 210,20
$Consigne.Size = New-Object System.Drawing.Size(1500,220)
$Form.Controls.Add($Consigne)
################################################################################################################
# $DesktopPath = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::Desktop)
# $TxtConsigne= (import-csv "$DesktopPath\consigne.csv" -encoding UTF8 -delimiter ";")
# $Message = ($TxtConsigne | where-object {$_.EXPIRATION -ge $today})
$Timer.Start()
if ($Message){
$Message | FOREACH{
$Mess += "- " + $_.Consigne + "`n"
$Consigne.Text = $Mess
}
$Mess=$null
#Affichage de la fenêtre uniquement si consigne à passer
[void]$Form.ShowDialog()
}
$Timer.Stop()
and content of consigne.csv
DATE;EXPIRATION;CONSIGNE; 12/09/20;15/09/20;Message 4;
11/09/20;11/09/20;Message 3; 10/09/20;11/09/20;Message 2;
10/09/20;10/09/20;Message 1;
You don't need all those $global:xxx variables in the Timer event handler; just one for the path to the CSV file would be enough. Also, it could do with a lesser scope: $script:xxx.
Then, you are comparing a date as formatted string in format dd/MM/yy which does not compare like you think, since the day comes earlier than the month. (it is a non-sortable date format).
Always try to compare datetime objects to other datetime objects.
Try:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[System.Windows.Forms.Application]::EnableVisualStyles();
# the path to the csv file used in the timer event handler.
$csvPath = Join-Path -Path ([Environment]::GetFolderPath("Desktop")) -ChildPath 'consigne.csv'
################ Form #####################################
#Form
$Form = New-Object System.Windows.Forms.Form
$Form.Location = New-Object System.Drawing.Point 0,570
$Form.Size = New-Object System.Drawing.Size(1920,260)
# Consigne
$Consigne = New-Object System.Windows.Forms.Label
$Consigne.Location = New-Object System.Drawing.Point 210,20
$Consigne.Size = New-Object System.Drawing.Size(1500,200)
$Form.Controls.Add($Consigne)
################ TIMER ##################################
$Timer = New-Object System.Windows.forms.timer
$Timer.Enabled = $false # disabled at first
$Timer.Interval = 50 # initial timer interval
# Timer Action.
$Timer.Add_Tick({
$this.Interval = 5000 # inside the event handler, you can refer to the control with `$this`
$Consigne.Text = [string]::Empty # clear the label
# read the CSV file, get the items with an EXPIRATION date greater
# or equal to today and write the CONSIGNE messages to the label
(Import-Csv -Path $script:csvPath -Encoding UTF8 -Delimiter ";") |
Where-Object { [datetime]::ParseExact($_.EXPIRATION, 'dd/MM/yy', $null) -ge (Get-Date).Date } |
ForEach-Object {$Consigne.Text += "- {0}`r`n" -f $_.CONSIGNE }
})
# start the timer as soon as the form is shown
$Form.Add_Shown({$Timer.Enabled = $true; $Timer.Start()})
[void]$Form.ShowDialog()
# clean up the Timer and Form objects
$Timer.Dispose()
$Form.Dispose()

How to change height of items in ListBox in powershell?

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)

PowerShell: Duplicate windows forms with different properties

I am trying make copies of windows forms objects and change the properties of new objects. For example:
$List1 = New-Object System.Windows.Forms.ListBox
$List1.Location = New-Object System.Drawing.Size(10,10)
$List1.Size = New-Object System.Drawing.Size(280,310)
$List2 = $List1
$List2.Location = New-Object System.Drawing.Size(350,10)
The problem is that $List2 is a pointer of $List1. Whatever I change on $List2 always change the properties on $List1. Is there a solution for this?
$List1.Location
IsEmpty X Y
------- - -
False 350 10
$List1.Location
IsEmpty X Y
------- - -
False 350 10
Whatever I change on $List2 always change the properties on $List1. Is there a solution for this?
Yes, the solution is to create a new instance of ListBox:
$List1 = New-Object System.Windows.Forms.ListBox
$List1.Location = New-Object System.Drawing.Size(10,10)
$List1.Size = New-Object System.Drawing.Size(280,310)
$List2 = New-Object System.Windows.Forms.ListBox
$List2.Size = $List1.Size
$List2.Location = New-Object System.Drawing.Size(350,10)
Notice that $List2.Size = $List1.Size is safe, because Size is a struct, and structs are copied on assignment
If you have many properties to reference, you could wrap the common property values in a hashtable to pass to New-Object -Property:
$ListBoxDefaultProperties = #{
Location = New-Object System.Drawing.Size (10,10)
Size = New-Object System.Drawing.Size (280,310)
BackColor = 'Beige'
DisplayMember = 'SomePropertyName'
# etc...
}
$List1 = New-Object System.Windows.Forms.ListBox -Property $ListBoxDefaultProperties
$List2 = New-Object System.Windows.Forms.ListBox -Property $ListBoxDefaultProperties
$List3 = New-Object System.Windows.Forms.ListBox -Property $ListBoxDefaultProperties
$List1 and $List2 reference the same object because you did $List1 = $List2.
You have to create 2 separate instances. You can set all common properties in a loop and then only change the properties that differ:
# 1. create two separate instances
$list1 = New-Object System.Windows.Forms.ListBox
$list2 = New-Object System.Windows.Forms.ListBox
# 2. set properties on both instances
foreach ($list in ($list1, $list2)) {
$list.Location = New-Object System.Drawing.Size(10, 10)
$list.Size = New-Object System.Drawing.Size(280, 310)
# [...]
}
# 3. set all different properties on the 2nd instance only
$list2.Location = New-Object System.Drawing.Size(350, 10)
# [...]

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

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