如何引用 ListBox 项
How do I reference a ListBox item
有时事情(PowerShell?)对我来说太聪明...
在这种情况下,我想更改 WinForms ListBox
item selected by its index (not the SelectedItems
). The point here is that $ListBox.Items[$CurrentIndex]
appears to be a [string]
type rather than an [Item]
类型的 Text
属性...
为此,我从我的大项目中创建了一个 mcve(带有上下文菜单):
using namespace System.Windows.Forms
$Form = [Form]@{ StartPosition = 'CenterScreen' }
$ListBox = [ListBox]@{}
@('one', 'two', 'three').ForEach{ $Null = $ListBox.Items.Add($_) }
$Form.Controls.Add($ListBox)
$ListBox.ContextMenuStrip = [ContextMenuStrip]@{}
$Context = $ListBox.ContextMenuStrip.Items.Add('ToUpper')
$ListBox.Add_MouseDown({ param($s, $e)
if ($e.Button -eq 'Right') { $Script:CurrentIndex = $ListBox.IndexFromPoint($e.Location) }
})
$Context.Add_Click({ param($s, $e)
if ($Null -ne $CurrentIndex) {
$Text = $ListBox.Items[$CurrentIndex]
Write-Host "I want to change text ""$Text"" of the item #$CurrentIndex to: ""$($Text.ToUpper())"""
# $ListBox.Items.Item[$CurrentIndex] = $Text.ToUpper()
}
})
$Form.ShowDialog()
如何更改例如$ListBox.Items[1]
("two
") 例如“TWO
”?
我实际上不确定这是否是与 PowerShell 相关的问题(类似于 #16878
Decorate dot selected Xml
strings (leaves) with XmlElement
methods where I would have an option to use the SelectNodes()
method) or related to WinForms itself: The answer might be in Gwt Listbox item reference to an Object 在这种情况下我不知道如何将其转换为 PowerShell。
您 可以 使用 $ListBox.Items.Item($CurrentIndex) = $Text.ToUpper()
修改存储的项目值 - 但就地修改 collection 项目不会触发 re-drawing ListBox
控件,所以看起来没有发生任何变化。
相反,修改 collection 本身 - 删除旧条目并在相同位置插入新条目:
$Context.Add_Click({ param($s, $e)
if ($Null -ne $CurrentIndex) {
$Text = $ListBox.Items[$CurrentIndex]
# Remove clicked item
$ListBox.Items.RemoveAt($CurrentIndex)
# Insert uppercased string value as new item at the same index
$ListBox.Items.Insert($CurrentIndex, $Text.ToUpper())
}
})
这将导致拥有的控件刷新并且更改将立即反映在 GUI 中
补充:
确实,问题不在于修改 .Items
集合本身 - $ListBox.Items[$CurrentIndex] = $Text.ToUpper()
工作正常。[1]
解决真正的问题 - ListBox
没有刷新以响应修改基础 .Items
集合 中的 现有项目 到位 (即使您调用 $ListBox.Refresh()
也不行),还有一种方法可以删除和 re-adding 项目:
您可以使用 数据绑定,方法是将 System.ComponentModel.BindingList`1
实例分配给列表框的 .DataSource
属性。
修改项目到位后,可以调用.ResetBindings()
方法让列表框自行刷新,如下图
注:
还有一个.ResetItem(int index)
方法用来执行item-specific刷新,但我无法让它工作;关于原因的指示表示赞赏。
.ResetBindings()
可以改变listbox的滚动状态,这也是下面代码显式保存和恢复的原因。但是,它会自动保留列表框的选择状态(删除和re-adding方法也必须手动管理)。
using namespace System.Windows.Forms
using namespace System.ComponentModel
Add-Type -AssemblyName System.Windows.Forms
$Form = [Form]@{ StartPosition = 'CenterScreen' }
$ListBox = [ListBox]@{}
# Define the items as a strongly typed array of item strings.
[string[]] $items = @('one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight')
# Wrap the array in a [BindingList[string]] instance
# and make it the listbox's data source.
$ListBox.DataSource = [BindingList[string]]::new($items)
$Form.Controls.Add($ListBox)
$ListBox.ContextMenuStrip = [ContextMenuStrip]@{}
$Context = $ListBox.ContextMenuStrip.Items.Add('ToUpper')
$ListBox.Add_MouseDown({ param($s, $e)
if ($e.Button -eq 'Right') { $Script:CurrentIndex = $ListBox.IndexFromPoint($e.Location) }
})
$Context.Add_Click({ param($s, $e)
if ($null -ne $CurrentIndex) {
# Modify the underlying array.
$items[$CurrentIndex] = $items[$CurrentIndex].ToUpper()
# To prevent unwanted scrolling during the refresh below,
# save and restore what item is currently shown at the top
# of the visible list portion.
$prevTopIndex = $ListBox.TopIndex
# Notify the listbox via the BindingList[string] instance that
# the items have changed.
# !! The following *item-specific* call does NOT work.
# !! $ListBox.DataSource.ResetItem($CurrentIndex)
$ListBox.DataSource.ResetBindings()
$ListBox.TopIndex = $prevTopIndex # Restore the scrolling state.
}
})
$Form.ShowDialog()
[1]
一般语法观察:冗长的替代方法是显式调用实现参数化属性 提供 index-based 访问权限:$ListBox.Items.Item($CurrentIndex)
。这适用于任何 IList
-实现集合类型,包括数组。但是,通常不需要这样做,因为 PowerShell 通过 直接索引 显示此类参数化属性。例如,给定数组 $a = 'foo', 'bar'
,$a.Item(1)
更自然地表示为 $a[1]
有时事情(PowerShell?)对我来说太聪明...
在这种情况下,我想更改 WinForms ListBox
item selected by its index (not the SelectedItems
). The point here is that $ListBox.Items[$CurrentIndex]
appears to be a [string]
type rather than an [Item]
类型的 Text
属性...
为此,我从我的大项目中创建了一个 mcve(带有上下文菜单):
using namespace System.Windows.Forms
$Form = [Form]@{ StartPosition = 'CenterScreen' }
$ListBox = [ListBox]@{}
@('one', 'two', 'three').ForEach{ $Null = $ListBox.Items.Add($_) }
$Form.Controls.Add($ListBox)
$ListBox.ContextMenuStrip = [ContextMenuStrip]@{}
$Context = $ListBox.ContextMenuStrip.Items.Add('ToUpper')
$ListBox.Add_MouseDown({ param($s, $e)
if ($e.Button -eq 'Right') { $Script:CurrentIndex = $ListBox.IndexFromPoint($e.Location) }
})
$Context.Add_Click({ param($s, $e)
if ($Null -ne $CurrentIndex) {
$Text = $ListBox.Items[$CurrentIndex]
Write-Host "I want to change text ""$Text"" of the item #$CurrentIndex to: ""$($Text.ToUpper())"""
# $ListBox.Items.Item[$CurrentIndex] = $Text.ToUpper()
}
})
$Form.ShowDialog()
如何更改例如$ListBox.Items[1]
("two
") 例如“TWO
”?
我实际上不确定这是否是与 PowerShell 相关的问题(类似于 #16878
Decorate dot selected Xml
strings (leaves) with XmlElement
methods where I would have an option to use the SelectNodes()
method) or related to WinForms itself: The answer might be in Gwt Listbox item reference to an Object 在这种情况下我不知道如何将其转换为 PowerShell。
您 可以 使用 $ListBox.Items.Item($CurrentIndex) = $Text.ToUpper()
修改存储的项目值 - 但就地修改 collection 项目不会触发 re-drawing ListBox
控件,所以看起来没有发生任何变化。
相反,修改 collection 本身 - 删除旧条目并在相同位置插入新条目:
$Context.Add_Click({ param($s, $e)
if ($Null -ne $CurrentIndex) {
$Text = $ListBox.Items[$CurrentIndex]
# Remove clicked item
$ListBox.Items.RemoveAt($CurrentIndex)
# Insert uppercased string value as new item at the same index
$ListBox.Items.Insert($CurrentIndex, $Text.ToUpper())
}
})
这将导致拥有的控件刷新并且更改将立即反映在 GUI 中
补充
确实,问题不在于修改 .Items
集合本身 - $ListBox.Items[$CurrentIndex] = $Text.ToUpper()
工作正常。[1]
解决真正的问题 - ListBox
没有刷新以响应修改基础 .Items
集合 中的 现有项目 到位 (即使您调用 $ListBox.Refresh()
也不行),还有一种方法可以删除和 re-adding 项目:
您可以使用 数据绑定,方法是将 System.ComponentModel.BindingList`1
实例分配给列表框的 .DataSource
属性。
修改项目到位后,可以调用.ResetBindings()
方法让列表框自行刷新,如下图
注:
还有一个
.ResetItem(int index)
方法用来执行item-specific刷新,但我无法让它工作;关于原因的指示表示赞赏。.ResetBindings()
可以改变listbox的滚动状态,这也是下面代码显式保存和恢复的原因。但是,它会自动保留列表框的选择状态(删除和re-adding方法也必须手动管理)。
using namespace System.Windows.Forms
using namespace System.ComponentModel
Add-Type -AssemblyName System.Windows.Forms
$Form = [Form]@{ StartPosition = 'CenterScreen' }
$ListBox = [ListBox]@{}
# Define the items as a strongly typed array of item strings.
[string[]] $items = @('one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight')
# Wrap the array in a [BindingList[string]] instance
# and make it the listbox's data source.
$ListBox.DataSource = [BindingList[string]]::new($items)
$Form.Controls.Add($ListBox)
$ListBox.ContextMenuStrip = [ContextMenuStrip]@{}
$Context = $ListBox.ContextMenuStrip.Items.Add('ToUpper')
$ListBox.Add_MouseDown({ param($s, $e)
if ($e.Button -eq 'Right') { $Script:CurrentIndex = $ListBox.IndexFromPoint($e.Location) }
})
$Context.Add_Click({ param($s, $e)
if ($null -ne $CurrentIndex) {
# Modify the underlying array.
$items[$CurrentIndex] = $items[$CurrentIndex].ToUpper()
# To prevent unwanted scrolling during the refresh below,
# save and restore what item is currently shown at the top
# of the visible list portion.
$prevTopIndex = $ListBox.TopIndex
# Notify the listbox via the BindingList[string] instance that
# the items have changed.
# !! The following *item-specific* call does NOT work.
# !! $ListBox.DataSource.ResetItem($CurrentIndex)
$ListBox.DataSource.ResetBindings()
$ListBox.TopIndex = $prevTopIndex # Restore the scrolling state.
}
})
$Form.ShowDialog()
[1]
一般语法观察:冗长的替代方法是显式调用实现参数化属性 提供 index-based 访问权限:$ListBox.Items.Item($CurrentIndex)
。这适用于任何 IList
-实现集合类型,包括数组。但是,通常不需要这样做,因为 PowerShell 通过 直接索引 显示此类参数化属性。例如,给定数组 $a = 'foo', 'bar'
,$a.Item(1)
更自然地表示为 $a[1]