#winforms #powershell #combobox #event-handling
#winforms #powershell #выпадающий список #обработка событий
Вопрос:
У меня есть ComboBox
элемент управления в моей форме. Я хочу, чтобы при изменении элемента в ComboBox
с одного на другой событие обрабатывалось. Важно, чтобы при изменении, а не при выборе одного и того же элемента. Все это время я пользовался ComboBox.Add_SelectionChangeCommitted($function)
, но вскоре понял, что блок, который также выполняется обработчиком при выборе того же (выбранного) элемента из списка. Немного покопавшись в событиях ComboBox, я совершенно запутался. Попробовав несколько событий ( SelectedItemChanged
, SelectedIndexChanged
), я никогда не мог достичь желаемого результата.
Пример того, что я хочу сделать и чего не следует делать несколько раз при выборе одного и того же элемента. Когда блок кода для ручного выполнения выполняется несколько раз, содержимое всех текстовых полей очищается, но я этого не хочу.
Add-Type -AssemblyName System.Windows.Forms
[System.Windows.Forms.Application]::EnableVisualStyles()
$Form = New-Object system.Windows.Forms.Form
$Form.ClientSize = '420,240'
$Form.TopMost = $false
$Form.FormBorderStyle = 'Fixed3D'
$Form.MaximizeBox = $false
$ComboBox = New-Object system.Windows.Forms.ComboBox
$ComboBox.width = 391
$ComboBox.height = 47
@('Automatic (DHCP)','Manual Input') | ForEach-Object {[void] $ComboBox.Items.Add($_)}
$ComboBox.location = New-Object System.Drawing.Point(13,57)
$ComboBox.DropDownStyle = 'DropDownList'
$ComboBox.DrawMode = 'OwnerDrawFixed'
$Button = New-Object system.Windows.Forms.Button
$Button.text = "Set"
$Button.width = 60
$Button.height = 30
$Button.visible = $false
$Button.enabled = $false
$Button.location = New-Object System.Drawing.Point(336,126)
$CheckBox = New-Object system.Windows.Forms.CheckBox
$CheckBox.width = 65
$CheckBox.height = 15
$CheckBox.visible = $false
$CheckBox.Checked = $false
$CheckBox.enabled = $true
$CheckBox.location = New-Object System.Drawing.Point(16,210)
$TextBox1 = New-Object system.Windows.Forms.TextBox
$TextBox1.Name = "TextBox1"
$TextBox1.multiline = $false
$TextBox1.width = 40
$TextBox1.height = 20
$TextBox1.visible = $false
$TextBox1.enabled = $true
$TextBox1.location = New-Object System.Drawing.Point(81,100)
$TextBox2 = New-Object system.Windows.Forms.TextBox
$TextBox2.Name = "TextBox2"
$TextBox2.multiline = $false
$TextBox2.width = 40
$TextBox2.height = 20
$TextBox2.visible = $false
$TextBox2.enabled = $false
$TextBox2.location = New-Object System.Drawing.Point(81,208)
$Form.controls.AddRange(@($TextBox1,$TextBox2,$Button,$ComboBox,$CheckBox))
$global:ManualChecked = $null
$global:AutomaticChecked = $null
$ComboBox.Add_SelectionChangeCommitted($methodSelection)
$netwValues = New-Object 'System.Collections.Hashtable'
$methodSelection =
{
switch($ComboBox.Text)
{
"Manual Input"
{
$CheckBox.Visible = $Button.Visible = $true
$Button.Enabled = $false
ForEach ($control in $Form.controls)
{
if ($control -is [System.Windows.Forms.TextBox] )
{
$control.Visible = $control.Enabled = $true
$control.Clear()
if($netwValues.Count -gt 0)
{
$control.Text = $netwValues.Item($control.Name)
$netwValues.Remove($control.Name)
}
}
}
if($global:ManualChecked -eq 1)
{
$CheckBox.Checked = $true
$TextBox2.Enabled = $true
}
else
{
$CheckBox.Checked = $false
$TextBox2.Enabled = $false
}
}
"Automatic (DHCP)"
{
ForEach($control in $Form.controls)
{
if($control -is [System.Windows.Forms.TextBox] -or $control -is [System.Windows.Forms.CheckBox] -or $control -is [System.Windows.Forms.Button])
{
$control.Visible = $control.Enabled = $true
if($control -is [System.Windows.Forms.Label] -or $control -is [System.Windows.Forms.TextBox])
{
$control.Enabled = $false
if($control -is [System.Windows.Forms.TextBox])
{
if($control.Text.Length)
{
$netwValues.Add($control.Name,$control.Text)
$control.Clear()
}
}
}
}
}
if($global:AutomaticChecked -eq 1)
{
$CheckBox.Checked = $true
}
else
{
$CheckBox.Checked = $false
}
}
}
}
Комментарии:
1. Просто возьмите глобальную переменную и сохраните в ней текущий выбранный индекс, при следующем событии проверьте предыдущий выбранный индекс, если он отличается, тогда делайте то, что вы хотите сделать
2. @Anil Разве смысл обработчиков событий не в том, что мы не храним кучу переменных bool и не проверяем их каждый раз?
3. @NikitaKobtsev Предполагая, что текст на каждом из ваших элементов в поле со списком отличается, вы можете использовать событие textchanged в поле со списком. Это событие вызывается не для одних и тех же элементов, но оно также не будет вызываться, если разные элементы имеют одинаковый текст 🙂
4. @Anil это работает не так. При изменении элемента изменяется индекс / значение (что вы, вероятно, хотите предложить) выбранного элемента, но не текст. Я тоже думал, что это
SelectedValueChanged
решит проблему, но нет, на самом деле блок кода выполняется дважды, я пробовал.5. Ну, когда вы меняете элемент в combobox, текст combobox также изменится и вызовет это событие comboBox1_TextChanged , это событие запускается только тогда и только тогда, когда текст изменился, при этом это означает, что оно не будет вызвано, если вы снова выберете тот же элемент, но также не сработает, если выбран другой элемент с тем же текстом. Также я знаю, что индекс / значение изменяется, когда мы выбираем новый элемент, но я, в частности, ссылался на изменение текстового свойства в combobox, а не на изменение индекса / значения, я все еще могу предположить, что это не то, что вы хотите, но дайте мне знать
Ответ №1:
Вы можете реализовать эту логику самостоятельно.
# Simple class for using as item for combobox instead of just string.
class CbItem
{
CbItem([string] $value)
{
$this.Value = $value
}
[string] $Value
[string] ToString()
{
return $this.Value
}
}
# Add instances of this class into combobox.
$ComboBox.Items.Add([CbItem]::new('Automatic (DHCP)'))
$ComboBox.Items.Add([CbItem]::new('Manual Input'))
# Create a variable for storing current combobox's item.
$global:CurrentCbItem = $null
# Add logic at the begining of handler for exiting if selected item is the same as the last one.
$methodSelection =
{
if ([Object]::ReferenceEquals($global:CurrentCbItem, $ComboBox.SelectedItem))
{
return
}
$global:CurrentCbItem = $ComboBox.SelectedItem
...
}