Powershell GUI not registering Radio Button as clicked [duplicate] - wpf

This question already has answers here:
WPF if statement based on radio button checked or not
(3 answers)
Closed 1 year ago.
I have the following code:
$var_executeButton.Add_Click( {
if ($var_radioButton.Checked) {
..do stuff
}
})
however, the code inside the if block never run, even if radio button is checked.
Code outside of the if works just fine.
Can you please tell me why?

Continuing from my comment. There ways to take action on form elements at the time they are acted on or checked later. As an example here is a simple WinForm, that discovers all radio button controls on a form and takes the same action when any one of them is clicked.
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$objForm = New-Object System.Windows.Forms.Form
$objForm.Text = "Test"
$objForm.Size = New-Object System.Drawing.Size(400, 200)
$objForm.StartPosition = "CenterScreen"
$RadioButton1 = New-Object System.Windows.Forms.RadioButton
$RadioButton1.Location = New-Object System.Drawing.Size(10, 10)
$RadioButton1.Size = New-Object System.Drawing.Size(100, 20)
$RadioButton1.Checked = $false
$RadioButton1.text = "Button1"
$objForm.controls.Add($RadioButton1)
$RadioButton2 = New-Object System.Windows.Forms.RadioButton
$RadioButton2.Location = New-Object System.Drawing.Size(10, 50)
$RadioButton2.Size = New-Object System.Drawing.Size(100, 20)
$RadioButton2.Checked = $false
$RadioButton2.text = "Button2"
$objForm.controls.Add($RadioButton2)
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(10, 120)
$OKButton.Size = New-Object System.Drawing.Size(150, 30)
$OKButton.Text = "OK"
$OKButton.Enabled = $false
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$objForm.Controls.Add($OKButton)
$objForm.AcceptButton = $OKButton
$objForm.TopMost = $True
$objForm.Controls |
Where-Object { $PSItem -is [System.Windows.Forms.RadioButton] } |
ForEach-Object {
$PSItem.Add_Click(
{
If (-Not $OKButton.Enabled)
{$OKButton.Enabled = $True}
})
}
$Form = $objForm.ShowDialog()
To see if a radio button is checked, you can use either .Checked,
# Example - check radio button state on OK click.
function Test-RadioButtonCheck
{
Param
(
$title,
$a1,
$a2,
$a3
)
$form = New-Object System.Windows.Forms.Form
$form.Size = '300,250'
$form.Text = $title
$form.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
$label1 = New-Object System.Windows.Forms.Label
$label1.Location = '15,15'
$label1.Width = 100
$label1.Text = 'Enter some text'
$form.Controls.Add($label1)
$textBox1 = New-Object System.Windows.Forms.TextBox
$textBox1.Location = '115,15'
$textBox1.width = 150
$textBox1.Name = 'input'
$form.Controls.Add($textBox1)
$radio1 = New-Object System.Windows.Forms.RadioButton
$radio1.Location = '25,40'
$radio1.Text = 'Check me if you want the save'
$radio1.Width = 200
$form.Controls.Add($radio1)
$button = New-Object System.Windows.Forms.Button
$button.Location = '70,70'
$button.Text = 'Ok'
$button.DialogResult = 'Ok'
$form.Controls.Add($button)
if($form.ShowDialog() -eq 'Ok')
{
if($textBox1.Text)
{
if($radio1.Checked){$form}
else{[void][System.Windows.Forms.MessageBox]::Show('You didn''t check the radio button','Error')}
}
else{[void][System.Windows.Forms.MessageBox]::Show('You didn''t enter any text','Error')}
}
}
if($frm = Test-RadioButtonCheck 'Test form')
{Write-Host "You entered $($frm.Controls['input'].Text)" -ForegroundColor Green}
.IsChecked as per mklement0's link, or looping to find them:
Where {$PSItem -is [system.windows.controls.radiobutton] -and $PSItem.IsChecked} |
Select Name
... or using [System.Windows.Controls.RadioButton]::CheckedEvent as per this WPF example:
[xml]$xaml = #"
<Window
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml"
x:Name = "Window" Title = "Initial Window" WindowStartupLocation = "CenterScreen"
SizeToContent = "WidthAndHeight" ShowInTaskbar = "True" Background = "lightgray">
<StackPanel x:Name = 'StackPanel'>
<RadioButton x:Name = "Item1" Content = 'Item1'/>
<RadioButton x:Name = "Item2" Content = 'Item2'/>
<RadioButton x:Name = "Item3" Content = 'Item3'/>
<Separator/>
<TextBox x:Name = 'textbox'/>
</StackPanel>
</Window>
"#
$reader = (New-Object System.Xml.XmlNodeReader $xaml)
$Window = [Windows.Markup.XamlReader]::Load( $reader )
$xaml.SelectNodes("//*[#*[contains(translate(name(.),'n','N'),'Name')]]") |
ForEach {Set-Variable -Name ($PSItem.Name) -Value $Window.FindName($PSItem.Name) -Scope Script}
#Bubble up event handler
[System.Windows.RoutedEventHandler]$Script:CheckedEventHandler =
{$TextBox.Text = $PSItem.source.name}
$StackPanel.AddHandler([System.Windows.Controls.RadioButton]::
CheckedEvent, $CheckedEventHandler)
$Window.Showdialog() | Out-Null
If you want dig at the explanations of the WPF and radio button options, then see this blog post regarding the samples shown:
https://learn-powershell.net/2014/08/10/powershell-and-wpf-radio-button
If the aforementioned is not what you are doing, then as per my comment, you are not showing what the use case really is.

Related

Powershell, WinForms and modal popup with faded background

I'm trying to implement a PowerShell form whereby there is a faded overlay over the background desktop.
The only way I could think implementing this was to use two forms - one to show a full screen overlay (background form), and the other being the actual (main) form. However, when i click off (or deactivate) the main form, I want everything to close. However it no longer closes and I can't figure it why? I get the feeling that when I click off the main form, the click event is trying to click the background form (and can't due to the main form having focus) and the 'deactivate' event no longer works?
Any help appreciated:
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[System.Windows.Forms.Application]::EnableVisualStyles()
$windowsGreyTrans = [System.Drawing.Color]::FromArgb(20,43,43,43)
$windowsGreyOff = [System.Drawing.Color]::FromArgb(43,43,43)
$windowsGreyOn = [System.Drawing.Color]::FromArgb(60,60,60)
$bgform = New-Object System.Windows.Forms.Form
$bgform.WindowState = 'Maximized'
$bgform.ShowInTaskbar = $false
$bgform.MaximizeBox = $false
$bgform.Opacity = 0.5
$bgform.ControlBox = $false
$bgform.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::none
[void]$bgform.show()
$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(200, 40)
$Form.StartPosition = "CenterScreen"
$form.ShowInTaskbar = $false
$form.Name ="Power"
$form.MaximizeBox = $false
$form.ControlBox = $false
$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::none
$shutdownBtn = New-Object System.Windows.Forms.Button
$shutdownBtn.Location = New-Object System.Drawing.Point(0, 0)
$shutdownBtn.Size = New-Object System.Drawing.Size(200, 40)
$shutdownBtn.Text = "Shut down"
$shutdownBtn.FlatStyle = "Flat"
$shutdownBtn.UseVisualStyleBackColor = $True
$shutdownBtn.BackColor = $windowsGreyOff
$shutdownBtn.FlatAppearance.BorderSize = 0
$shutdownBtn.ForeColor = "White"
$shutdownBtn.Font = "Segoe UI,10pt"
#$shutdownBtn.Cursor = [System.Windows.Forms.Cursors]::Hand
$shutdownBtn.Add_Click({
try {
}
catch{
}
})
$shutdownBtn.Add_MouseEnter({
$this.BackColor = $windowsGreyOn
})
$shutdownBtn.Add_MouseLeave({
$this.BackColor = $windowsGreyOff
})
$form.Controls.Add($shutdownBtn)
$form.Add_Deactivate({
$this.Close()
$bgform.close()
})
$form.Add_Shown({
$this.Activate()
})
[void]$form.showdialog()
I propose you a better solution, use a tablelayoutpanel for center your button and intercept click event.
Try this :
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
[System.Windows.Forms.Application]::EnableVisualStyles()
$windowsGreyTrans = [System.Drawing.Color]::FromArgb(20,43,43,43)
$windowsGreyOff = [System.Drawing.Color]::FromArgb(43,43,43)
$windowsGreyOn = [System.Drawing.Color]::FromArgb(60,60,60)
#create form
$form = New-Object System.Windows.Forms.Form
$form.SuspendLayout()
$form.WindowState = [System.Windows.Forms.FormWindowState]::Maximized
$form.ShowInTaskbar = $false
$form.MaximizeBox = $false
$form.Opacity = 0.5
$form.ControlBox = $false
$form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::none
#create Tablelayout panel on this form
$TableLayoutPanel = New-Object System.Windows.Forms.TableLayoutPanel
$TableLayoutPanel.SuspendLayout()
$TableLayoutPanel.ColumnCount=1
$TableLayoutPanel.RowCount=1
$TableLayoutPanel.Dock=[System.Windows.Forms.DockStyle]::Fill
$form.Controls.Add($TableLayoutPanel)
#create button on this tablelayoutpanel
$shutdownBtn = New-Object System.Windows.Forms.Button
$shutdownBtn.Size = New-Object System.Drawing.Size(200, 40)
$shutdownBtn.Text = "Shut down"
$shutdownBtn.FlatStyle = "Flat"
$shutdownBtn.UseVisualStyleBackColor = $True
$shutdownBtn.BackColor = $windowsGreyOff
$shutdownBtn.FlatAppearance.BorderSize = 0
$shutdownBtn.ForeColor =[System.Drawing.Color]::White
$shutdownBtn.Font = "Segoe UI,10pt"
$shutdownBtn.Anchor=[System.Windows.Forms.AnchorStyles]::None
$TableLayoutPanel.Controls.Add($shutdownBtn)
#Layout
$TableLayoutPanel.ResumeLayout($false)
$form.ResumeLayout($false)
$shutdownBtn.Add_Click({
try {
}
catch{
}
})
#change color to tablelayot on first show
$form.Add_Shown({
$TableLayoutPanel.BackColor =$windowsGreyTrans
})
$TableLayoutPanel.Add_Click({
$form.close()
})
$shutdownBtn.Add_MouseEnter({
$this.BackColor = $windowsGreyOn
})
$shutdownBtn.Add_MouseLeave({
$this.BackColor = $windowsGreyOff
})
[void]$form.ShowDialog()
$form.Dispose()

How can i lock a form in position on the desktop?

I'm trying to make a form in PowerShell that gets locked to a fixed position on the desktop.
Because whenever I press the "Show Desktop" button on the bottom right corner on Win 8.1, the form disappears until I open a different window and close it.
I just want it there like it's a widget, here's a part of the code i'm using:
Add-Type -AssemblyName System.Windows.Forms
Add-Type -Assembly System.Drawing
$Image = [System.Drawing.Image]::Fromfile("Panel.png")
$Form = New-Object system.Windows.Forms.Form
$Form.BackgroundImage = $Image
$Form.BackgroundImageLayout = "None"
$Form.Text = "Reboot Server"
$Form.Width = 517
$Form.Height = 134
$Form.ControlBox = $False
$Form.StartPosition = 'Manual'
$Form.Location = "1390, 300"
$Form.FormBorderStyle = 'None'
$Form.BackColor = "#000000"
$Form.MaximizeBox = $False
$Form.MinimizeBox = $False
$Form.Icon = "icon.ico"
$Form.Image = [System.Drawing.Image]::Fromfile("Panel.png")
$Form.ShowInTaskbar = $False
$Font = New-Object System.Drawing.Font("Tahoma",10, [System.Drawing.FontStyle]::Bold)
$Form.Font = $Font
$Label = New-Object System.Windows.Forms.Label
$Label.Text = ""
$Label.AutoSize = $True
$Form.Controls.Add($Label)
' Button 1 - Reboot Server'
$Button1 = new-object System.Windows.Forms.Button
$Button1.Location = new-object System.Drawing.Size(234,51)
$Button1.Size = new-object System.Drawing.Size(77,55)
$Button1.AutoSize = $True
$Button1.Add_Click({start-process "Reboot.lnk"})
$Button1.FlatStyle = [System.Windows.Forms.FlatStyle]::Flat
$Button1.FlatAppearance.BorderSize=0
$Button1.BackColor = "Transparent"
$Button1.ForeColor = "Transparent"
$Button1.FlatAppearance.MouseDownBackColor = "Transparent"
$Button1.FlatAppearance.MouseOverBackColor = "Transparent"
$Button1.FlatAppearance.BorderColor = "#252525"
$Form.Controls.Add($Button1)
'----------------------------------------
$Form.ShowDialog() | Out-Null
Exit 0
For gadget style positions try to use a little snippet that I have made:
$Poistion = 'RightBottom'
$Coordinates = switch ($Poistion)
{
'LeftTop' { 0, 0 }
'LeftBottom' { 0, $([System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea.Bottom - $Form.Height) }
'RightTop' { $([System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea.Width - $Form.Width), 0 }
'RightBottom' { $([System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea.Width - $Form.Width), $([System.Windows.Forms.Screen]::PrimaryScreen.WorkingArea.Bottom - $Form.Height) }
}
$Form.Location = New-Object System.Drawing.Point($Coordinates)
To keep your form up at the time when you activate "Show Desktop" set TopMost property to $True and MinimizeBox property to $False. Like so:
$Form.TopMost = $True
$Form.MinimizeBox = $False
When you click on Show Desktop or use its hotkey (Win+D) windows tries to send Minimize All command to running applications. After minimizing all the windows that can be minimized, it then takes the desktop and "raises" it to the top of the window stack so that no other windows cover it.
You could also try to use sizing events. Like so:
$Form_Resize={
$Form.WindowState = 'Normal'
}
$Form.add_Resize($Form_Resize)

Build and respond to events on multiple check boxes

I am attempting to make a form with multiple check boxes, based on the array passed to the form creation function. I can calculate the correct location based on the count of what checkbox I am at is, but I am having trouble (I think) dealing with events. I have this for now (partial code, obviously)
$checkboxCount = 1
foreach ($year in $years) {
$checkbox = new-object System.Windows.Forms.checkbox
$checkbox.Size = new-object System.Drawing.Size(100,20)
$checkbox.Location = new-object System.Drawing.Size(10,($checkbox.Size.Height*$checkboxCount-10))
$checkbox.Text = "Revit $year"
$checkbox.Checked = $true
$Form.Controls.Add($checkbox)
$checkbox.Add_CheckStateChanged({
$results.$year = $checkbox.Checked
})
$checkboxCount ++
}
and the check boxes are created correctly, but when I return $results from the function they are all True. I am basing the code off of this, which works but with a static number of check boxes.
function checkbox_test{
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$results = #{
one = $true
two = $true
}
$optionCount = 2
# Set the size of your form
$Form = New-Object System.Windows.Forms.Form
$Form | Format-List *
$form.FormBorderStyle = 'FixedDialog'
$form.ShowInTaskbar = $false
$Form.width = 300
$Form.height = 150
$Form.Text = ”Px Tools Updater”
# Set the font of the text to be used within the form
$Font = New-Object System.Drawing.Font("Times New Roman",12)
$Form.Font = $Font
# create your checkbox
$checkbox1 = new-object System.Windows.Forms.checkbox
$checkbox1.Location = new-object System.Drawing.Size(10,7)
$checkbox1.Size = new-object System.Drawing.Size(100,20)
$checkbox1.Text = "One"
$checkbox1.Checked = $true
$Form.Controls.Add($checkbox1)
# create your checkbox
$checkbox2 = new-object System.Windows.Forms.checkbox
$checkbox2.Location = new-object System.Drawing.Size(10,27)
$checkbox2.Size = new-object System.Drawing.Size(100,20)
$checkbox2.Text = "Two"
$checkbox2.Checked = $true
$Form.Controls.Add($checkbox2)
# Add an OK button
$OKButton = new-object System.Windows.Forms.Button
$OKButton.Location = new-object System.Drawing.Size(10,70)
$OKButton.Size = new-object System.Drawing.Size(60,30)
$OKButton.Text = "OK"
$OKButton.Add_Click({$Form.Close()})
$form.Controls.Add($OKButton)
#Add a cancel button
$CancelButton = new-object System.Windows.Forms.Button
$CancelButton.Location = new-object System.Drawing.Size(225,100)
$CancelButton.Size = new-object System.Drawing.Size(60,30)
$CancelButton.Text = "Cancel"
$CancelButton.Margin = 0
$CancelButton.Add_Click({$Form.Close()})
$form.Controls.Add($CancelButton)
$checkbox1.Add_CheckStateChanged({
$results.one = $checkbox1.Checked
})
$checkbox2.Add_CheckStateChanged({
$results.two = $checkbox2.Checked
})
# Activate the form
$Form.Add_Shown({$Form.Activate()})
[void] $Form.ShowDialog()
$results
}
I am not sure if I am going wrong with the way I am referencing the results hash table, or maybe the entire approach is wrong?
Edit: I had a thought, that $year is meaningless in the event handler, so I added
$checkbox.Name = $year
and revised the event handler to
$results.($checkbox.Name) = $checkbox.Checked
and
$results.($Self.Name) = $checkbox.Checked
But no joy with either. But what is weird is that using $self results in an odd extra key being added to $return. It has no key name, but the value matches the last change made to any checkbox.
EDIT #2: In further testing, I changed the handler to
$results.2019 = $checkbox.Checked
expecting that to mean any change results in that change applied to the 2019 key. not so. So I am thinking it relates to the way hash tables are passed and referenced and likely I am doing this all wrong. Perhaps worrisome is the fact that I can find tons of information on making check boxes react to and change other parts of the form, but so far nothing on just getting results back.
EDIT #3: OK, seems the answer (of sorts) is there is no need for event handlers, because I only really care about end state anyway. So, with some extra cleanup to also handle Cancel I have this, and it works. Still curious how, or if, I could interact directly with $results from an event handler though.
function checkbox_test{
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
$years = #('2016', '2017', '2018', '2019')
$optionCount = $years.Count
# Set the size of your form
$Form = New-Object System.Windows.Forms.Form
$form.FormBorderStyle = 'FixedDialog'
$form.ShowInTaskbar = $false
$Form.width = 300
$Form.height = ($years.Count * 30 + 50 + 40) #150
$Form.Text = ”Px Tools Updater”
# Set the font of the text to be used within the form
$Font = New-Object System.Drawing.Font("Times New Roman",12)
$Form.Font = $Font
# create Checkboxes
$checkboxCount = 1
foreach ($year in $years) {
$checkbox = new-object System.Windows.Forms.checkbox
$checkbox.Size = new-object System.Drawing.Size(100,20)
$checkbox.Location = new-object System.Drawing.Size(10,($checkbox.Size.Height*$checkboxCount-10))
$checkbox.Text = "Revit $year"
$checkbox.Name = $year
$checkbox.Checked = $true
$Form.Controls.Add($checkbox)
$checkboxCount ++
}
# Add an OK button
$OKButton = new-object System.Windows.Forms.Button
$OKButton.Size = new-object System.Drawing.Size(60,30)
$OKButton.Location = new-object System.Drawing.Size(10,($form.DisplayRectangle.Height - $OKButton.Size.Height - 10))
$OKButton.Text = "OK"
$OKButton.Add_Click({
$Form.DialogResult = [System.Windows.Forms.DialogResult]::OK
$Form.Close()
})
$form.Controls.Add($OKButton)
#Add a cancel button
$CancelButton = new-object System.Windows.Forms.Button
$CancelButton.Size = new-object System.Drawing.Size(60,30)
$CancelButton.Location = new-object System.Drawing.Size(($form.DisplayRectangle.Width - $CancelButton.Size.Width - 10),($form.DisplayRectangle.Height - $CancelButton.Size.Height - 10))
$CancelButton.Text = "Cancel"
$CancelButton.Add_Click({
$Form.Close()
})
$form.Controls.Add($CancelButton)
# Activate the form
$Form.Add_Shown({$Form.Activate()})
if ($Form.ShowDialog() -eq 'OK') {
$results = New-Object Collections.Specialized.OrderedDictionary
foreach ($control in $form.Controls) {
if ($years -contains $control.Name) {
$results.Add($control.Name, $control.Checked)
}
}
} else {
$results = $null
}
[void] $Form.Dispose
$results
}
#Call the function
$returned = checkbox_test
Foreach ($key in $returned.keys) {
Write-Host "[$key] $($returned.$key)!"
}
The foreach loop used to assign each checkbox event handler above effectively overwrites the previous one, and therefore you only capture the last one. (2019)
Instead, assign the event hander the way it's traditionally done in Windows Forms:
$results = New-Object Collections.Specialized.OrderedDictionary;
foreach ($year in $years) {
$checkbox = new-object System.Windows.Forms.checkbox
$Form.Controls.Add($checkbox);
$checkbox.Size = new-object System.Drawing.Size(100,20)
$checkbox.Location = new-object System.Drawing.Size(10,($checkbox.Size.Height*$checkboxCount-10))
$checkbox.Text = "Revit $year"
$checkbox.Name = $year
$checkbox.Checked = $true
$results.Add($year, $checkbox.Checked);
# HERE!
$checkbox.Add_CheckStateChanged({
# $this -eq sender, optionally $_ -eq EventArgs
$year = $this.name;
$results.$year = $this.Checked;
});
$checkboxCount++
}

PowerShell DataGridView ComboBoxColumn Default Value

I'm trying to set the default value for DataGridViewComboBoxColumn to be a variable, but I can't find which property to set.
$Column2 = New-Object System.Windows.Forms.DataGridViewComboBoxColumn
$Column2.width = 60
$Column2.name = "Status"
$Column2.DataSource = $DropDownArray
$DataGrid.Columns.Add($Column2)
I've tried:
$Column2.Value = "C"
$Column2.ValueMember = $DDI
$Column2.DataPropertyName = $DDI
$Column2.DisplayMember = $DDI
$Column2.Text = $DropDown.SelectedItem
If($Column2.Index -ge "0"){$Column2.ValueMember = "C"}
$DDI calls back to an array item.
Assistance is appreciated.
Edit
I am not communicating this well enough, I assume. Here is what I have so far (ignore all the commented out stuff, of course):
$null=[reflection.assembly]::LoadWithPartialName("System.Windows.Forms")
$null=[reflection.assembly]::LoadWithPartialName("System.Drawing")
#Initialize DataGrid stuff
$form = new-object System.Windows.Forms.Form
$form.Size = new-object System.Drawing.Size 800,400
$DataGrid = new-object System.Windows.Forms.DataGridView
#$DataGrid = new-object System.windows.forms.DataGrid
$DataGrid.AutoSize = $True
$DataGrid.EditMode = 'EditOnEnter'
#$DataGrid.BeginEdit()
[array]$DropDownArray = "FVR","C","O","P"
#$DropDownArray = #(Import-Csv "$BkpLoc\array.csv")
#This creates the Ok button and sets the event
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size(750,375)
$OKButton.Size = New-Object System.Drawing.Size(150,125)
$OKButton.Text = "OK"
$OKButton.Add_Click({$form.Close()})
$OKButton.TabIndex = 9
$array= new-object System.Collections.ArrayList
$data=#(Import-CSV $SAMTemp2)
$array.AddRange($data)
$DataGrid.DataSource = $array
#$DataGrid.Columns.Remove($array.Status)
#Figure out how to set the array to read-only
#$array.IsReadOnly
$Column1 = New-Object System.Windows.Forms.DataGridViewCheckBoxColumn
$Column1.width = 60
$Column1.name = "Planned"
$DataGrid.Columns.Add($Column1)
$Column2 = New-Object System.Windows.Forms.DataGridViewComboBoxColumn
$Column2.width = 60
$Column2.name = "Status"
$Column2.DataSource = $DropDownArray
$DataGrid.Columns.Add($Column2)
#$Column2.Selected = $DropDownArray[1]
#$Column2.DisplayMember = "Status"
#$Column2.DataPropertyName = $DropDownArray[1]
#$Column2.ValueMember = $DropDownArray.Item(1)
$array = New-Object System.Collections.ArrayList
$form.refresh()
#finally show display the Grid
$DataGrid.Dock = [System.Windows.Forms.DockStyle]::Fill
$form.Controls.Add($DataGrid)
$form.controls.add($OKButton)
$form.topmost = $true
$null = $form.showdialog()
My goal here is to have $Column1 available to check if the task was planned that day (up to the user) and $Column2 to default to the status in the export (FVR, C, O or P), allowing the user to change it to another option if the data is incorrect. So ultimately I would like the default to be set based on a statement like:
If($_.Status -eq "Open"){$Column2.ValueMember = <WHATEVER IT TAKES TO GET THE CURRENT VALUE TO "O">
$Column2.DataPropertyName = <WHATEVER IT TAKES TO GET THE CURRENT VALUE TO "O">
$Column2.DisplayMember = <WHATEVER IT TAKES TO GET THE CURRENT VALUE TO "O">
And the same for each value. ($_.Status is one of the columns in the imported CSV.) Right now I just can't get it right. Should there be more to my array than just the 4 values? Everything I try right now for ValueMember comes back saying Field called -WHATEVER- does not exist.
When you add rows to or data bind your DataGridView you will specify the default or selected value for that column then and it'll get translated to your combobox. ValueMember is what you're looking for as it's associated with the data's actual value as opposed to what's displayed in the combobox (DisplayMember). ValueMember and DisplayMember can be the same but they don't have to be.
See below example. This will create a data source of color names and RGB values.
# Datatable for your CSV content
$DataTable1 = New-Object System.Data.DataTable
[void] $DataTable1.Columns.Add("Fruit")
[void] $DataTable1.Columns.Add("RGB")
# Your CSV content
#"
Fruit,RGB
apple,ff0000
apple,00ff00
kiwi,00ff00
"# | ConvertFrom-Csv | ForEach-Object {
[void] $DataTable1.Rows.Add($_.Fruit, $_.RGB)
}
# Acceptable color values datatable - for your combobox
$DataTable2 = New-Object System.Data.DataTable
[void] $DataTable2.Columns.Add("RGB")
[void] $DataTable2.Columns.Add("Color")
# Manually add rows. You can programmatically add the rows as well
[void] $DataTable2.Rows.Add("ff0000", "red")
[void] $DataTable2.Rows.Add("00ff00", "green")
[void] $DataTable2.Rows.Add("0000ff", "blue")
# Form
$Form = New-Object System.Windows.Forms.Form
$Form.Size = New-Object System.Drawing.Size(500,500)
$Form.StartPosition = "CenterScreen"
# Form event handlers
$Form.Add_Shown({
$Form.Activate()
})
# Datagridview
$DGV = New-Object System.Windows.Forms.DataGridView
$DGV.Anchor = [System.Windows.Forms.AnchorStyles]::Right -bor [System.Windows.Forms.AnchorStyles]::Bottom -bor [System.Windows.Forms.AnchorStyles]::Left -bor [System.Windows.Forms.AnchorStyles]::Top
$DGV.Location = New-Object System.Drawing.Size(0,0)
$DGV.Size = New-Object System.Drawing.Size(480,400)
$DGV.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",10,0,3,1)
$DGV.BackgroundColor = "#ffffffff"
$DGV.BorderStyle = "Fixed3D"
$DGV.AlternatingRowsDefaultCellStyle.BackColor = "#ffe6e6e6"
$DGV.AutoSizeColumnsMode = [System.Windows.Forms.DataGridViewAutoSizeColumnsMode]::Fill
$DGV.AutoSizeRowsMode = [System.Windows.Forms.DataGridViewAutoSizeRowsMode]::AllCells
$DGV.SelectionMode = [System.Windows.Forms.DataGridViewSelectionMode]::FullRowSelect
$DGV.ClipboardCopyMode = "EnableWithoutHeaderText"
$DGV.AllowUserToOrderColumns = $True
$DGV.DataSource = $DataTable1
$DGV.AutoGenerateColumns = $False
$Form.Controls.Add($DGV)
# Datagridview columns
$Column1 = New-Object System.Windows.Forms.DataGridViewTextBoxColumn
$Column1.Name = "Fruit"
$Column1.HeaderText = "Fruit"
$Column1.DataPropertyName = "Fruit"
$Column1.AutoSizeMode = "Fill"
$Column2 = New-Object System.Windows.Forms.DataGridViewComboBoxColumn
$Column2.Name = "Color"
$Column2.HeaderText = "Color"
$Column2.DataSource = $DataTable2
$Column2.ValueMember = "RGB"
$Column2.DisplayMember = "Color"
$Column2.DataPropertyName = "RGB"
$DGV.Columns.AddRange($Column1, $Column2)
# Button to export data
$Button = New-Object System.Windows.Forms.Button
$Button.Anchor = [System.Windows.Forms.AnchorStyles]::Left -bor [System.Windows.Forms.AnchorStyles]::Bottom
$Button.Location = New-Object System.Drawing.Size(10,420)
$Button.Text = "Export"
$Form.Controls.Add($Button)
# Button event handlers
$Button.Add_Click({
$DataTable1 | Out-GridView # do what you want
})
# Show form
[void] $Form.ShowDialog()

.Bottom is read-only

I'm working on a PowerShell script that uses forms and panels that are docked. I was able to create the form and panels just fine, but I'm having issues getting a listbox to resize during runtime using $inputbox.Bottom = $form.Height - 215 to control the size, but I recieve the error
'Bottom' is a read-only property.
Simply using Fill in the panel will not work because I have buttons above and below the listbox. Here is a sample of my code:
[void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)
[void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Drawing”)
$form.ResizeEnd
$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(1040,459)
$form.KeyPreview = $true
$form.StartPosition = ‘centerscreen’
$form.BackColor = 'MidnightBlue'
$form.Add_KeyDown({if($_.KeyCode -eq "Escape"){$form.Close()}})
$form.Text = "Dialog Box 2.0"
$form.Icon = [system.drawing.icon]::ExtractAssociatedIcon($PSHOME + "\powershell_ise.exe")
$buttonPanel3 = New-Object Windows.Forms.Panel
$buttonPanel3.Size = New-Object Drawing.Size #(290,70)
$buttonPanel3.Dock = "left"
$buttonPanel3.BackColor = 'Blue'
$inputbox = New-Object System.Windows.Forms.ListBox
$inputbox.BorderStyle = 'NONE'
$inputbox.Font = New-Object System.Drawing.Font(“segoe UI”,9)
$inputbox.SelectionMode = "MultiExtended"
$inputbox.Left = 10
$inputbox.Top = 105
$inputbox.Width = 200
$inputbox.Bottom = $form.Height -215
$inputbox.Height = $form.Height -215
$buttonPanel3.Controls.Add($inputbox)
$form.Controls.Add($buttonPanel3)
$form.ShowDialog()
If someone could give some sample code of a listbox that resizes (mainly concerned with vertical expansion) when you resize the form that would be excellent.
I ended up completely rearranging my form and using the fill method, but I wanted to put in a tidbit about form resizing since that was the true issue here.
The resize handler for the form would be $form.Add_Resize({}). Inside the brackets I could modify the height and width properties as desired. In this case, I only wanted the height property, so the code would be like:
[void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Windows.Forms”)
[void] [System.Reflection.Assembly]::LoadWithPartialName(“System.Drawing”)
$form.ResizeEnd
$form = New-Object System.Windows.Forms.Form
$form.Size = New-Object System.Drawing.Size(1040,459)
$form.KeyPreview = $true
$form.StartPosition = ‘centerscreen’
$form.BackColor = 'MidnightBlue'
$form.Add_KeyDown({if($_.KeyCode -eq "Escape"){$form.Close()}})
$form.Text = "Dialog Box 2.0"
$form.Icon = [system.drawing.icon]::ExtractAssociatedIcon($PSHOME + "\powershell_ise.exe")
$form.Add_Resize({
$inputbox.Height = $form.Height -215
})
$buttonPanel3 = New-Object Windows.Forms.Panel
$buttonPanel3.Size = New-Object Drawing.Size #(290,70)
$buttonPanel3.Dock = "left"
$buttonPanel3.BackColor = 'Blue'
$inputbox = New-Object System.Windows.Forms.ListBox
$inputbox.BorderStyle = 'NONE'
$inputbox.Font = New-Object System.Drawing.Font(“segoe UI”,9)
$inputbox.SelectionMode = "MultiExtended"
$inputbox.Left = 10
$inputbox.Top = 105
$inputbox.Width = 200
$inputbox.Height = $form.Height -215
$buttonPanel3.Controls.Add($inputbox)
$form.Controls.Add($buttonPanel3)
$form.ShowDialog()

Resources