我试图通过PowerShell搜索WPF DataGrid,选择并突出显示包含搜索关键字的单元格,每个单元格依次出现。目标是1)搜索DataGrid,2)选择并突出显示包含搜索关键字的单元格,同时将焦点/滚动移动到包含列/单元格的行,以及3)对可能包含的其他任何列/单元格重复相同的操作相同的关键字。
我整理了一个示例脚本(请参见下文)以演示到目前为止的操作。在下面显示的示例脚本中,我能够搜索并找到包含关键字的行,然后滚动到该行。但是,我不知道如何突出显示该行上包含关键字的单元格。
下面显示的示例数据具有用于演示目的的预定义列。但是,从后端返回的实际数据是动态的,因此列数,列标题会有所不同,任何列都可能包含关键字。我们如何选择包含关键字的单元格?有没有更好的方法可以实现这一总体目标?预先感谢您的帮助。
[xml]$xaml=@"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Test"
Title="MainWindow" Height="175" Width="550">
<Grid>
<TextBox x:Name="tb_Search" HorizontalAlignment="Left" Height="23" Margin="10,10,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="149"/>
<Button x:Name="bt_Search" Content="Search" HorizontalAlignment="Left" VerticalAlignment="Top" Width="100" IsDefault="True" Height="22" Margin="165,10,0,0" />
<DataGrid x:Name="dg" Margin="10,45,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinHeight="100" Height="Auto" Width="Auto" ColumnWidth="Auto" AlternationCount="1" IsReadOnly="True" SelectionMode="Extended" SelectionUnit="Cell" Background="White" />
</Grid>
</Window>
"@
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$Window=[Windows.Markup.XamlReader]::Load($reader)
#Turn XAML into PowerShell objects
$xaml.SelectNodes("//*[@*[contains(translate(name(.),'n','N'),'x:Name')]]") | ForEach-Object{
Set-Variable -Name ($_.Name) -Value $Window.FindName($_.Name)
}
#sample data
$DataSet = New-Object System.Data.DataSet
$Table = $DataSet.Tables.Add("Table")
$Properties = @("Country","Capital","Population")
$Properties | foreach {
$Column = New-Object System.Data.DataColumn($_)
$Table.Columns.Add($Column)
}
$Null=$Table.Rows.Add("China PR","Beijing","20,693,000")
$Null=$Table.Rows.Add("India","New Delhi","16,787,949")
$Null=$Table.Rows.Add("Japan","Tokyo","13,189,000")
$Null=$Table.Rows.Add("Philippines","Manila","12,877,253")
$Null=$Table.Rows.Add("Russia","Moscow","11,541,000")
$Null=$Table.Rows.Add("Egypt","Cairo","10,230,350")
$Null=$Table.Rows.Add("USA","Washington, D.C","658,893")
$Null=$Table.Rows.Add("China PR","Beijing","20,693,000")
$Null=$Table.Rows.Add("India","New Delhi","16,787,949")
$Null=$Table.Rows.Add("Japan","Tokyo","13,189,000")
$Null=$Table.Rows.Add("Philippines","Manila","12,877,253")
$Null=$Table.Rows.Add("Russia","Moscow","11,541,000")
$Null=$Table.Rows.Add("Egypt","Cairo","10,230,350")
$Null=$Table.Rows.Add("USA","Washington, D.C","658,893")
#populate datagrid
$DataView = New-Object System.Data.DataView($Table)
$array = New-Object System.Collections.ArrayList
[void] $array.AddRange($DataView)
$dg.clear()
$dg.ItemsSource = $array
$dg.IsReadOnly = $true
$bt_Search.Add_Click({
$SearchValue = $tb_Search.text
for ($i = 0; $i -lt $dg.Items.Count; $i++)
{
if ($dg.Items[$i].Row[$dg.Columns.DisplayIndex] -eq "$SearchValue")
{
[System.Windows.Forms.MessageBox]::Show("Keyword Found")
$dg.ScrollIntoView($dg.Items[$i]) #scroll to the row that contains the keyword searched
}
}
})
#Display Form
$Window.ShowDialog() | Out-Null
答案 0 :(得分:1)
使用与您正在执行的操作非常相似的方法,我能够使它突出显示包含搜索短语的所有单元格(因为我一开始误解了这个问题)。我要做的是遍历各列,而不是一次为每一行搜索所有列。这样,我们就知道所需信息在哪一列中,然后在将正确的行滚动到视图中之后,可以在该列中选择单元格。
$bt_Search.Add_Click({
$SearchValue = $tb_Search.text
$dg.SelectedCells.Clear()
for ($i = 0; $i -lt $dg.Items.Count; $i++)
{
0..($dg.Columns.Count-1)|?{$dg.Items[$i].Row[$_] -eq "$SearchValue"}|%{
$dg.ScrollIntoView($dg.Items[$i],$dg.Columns[$_])
$DGCell = $dg.Columns[$_].GetCellContent($dg.Items[$i]).Parent
$DGCellInfo = New-Object System.Windows.Controls.DataGridCellInfo($DGCell)
$dg.SelectedCells.add($DGCellInfo)
}
}
})
这至少为您选择一个单元格打下了基础,您只需要弄清楚如何跟踪当前单元格即可继续前进到下一个单元格,因为听起来好像您希望能够移动一遍又一遍地单击“搜索”按钮,即可在单元格之间切换。
编辑:关于将其设置为执行“查找/查找下一步”的操作,您可以设置一个全局变量,将$i
设置为该变量,然后在您的内部设置该全局变量每次循环。然后,只要您有匹配项,就运行break
杀死循环,它应该从中断的地方开始。可能还希望在循环之前添加一行以重置全局变量,以便在结束时重新开始。这样的事情应该做到:
$global:SearchIndex = 0
$bt_Search.Add_Click({
$SearchValue = $tb_Search.text
$dg.SelectedCells.Clear()
for ($i = $global:SearchIndex; $i -lt $dg.Items.Count; $i++)
{
0..($dg.Columns.Count-1)|?{$dg.Items[$i].Row[$_] -eq "$SearchValue"}|%{
$dg.ScrollIntoView($dg.Items[$i],$dg.Columns[$_])
$DGCell = $dg.Columns[$_].GetCellContent($dg.Items[$i]).Parent
$DGCellInfo = New-Object System.Windows.Controls.DataGridCellInfo($DGCell)
$dg.SelectedCells.add($DGCellInfo)
$global:SearchIndex = $i
break
}
}
#check if we hit the end of the table. If we did display a notice and reset the search index.
If($global:SearchIndex -ge $dg.Items.Count){
[System.Windows.Forms.MessageBox]::Show("No more matches found, resetting search to begining of table.")
$global:SearchIndex=0
}
})
Edit2 :好吧,break
停止递增,因此每次都将找到相同的结果。为了解决这个问题,我们还需要跟踪列。如果我们也将内部循环更改为For
循环,则每次跟踪时都可以增加内部循环。我们还需要跟踪中断,因此如果内部循环中断,外部循环也会中断。因此,应该执行以下操作:
$global:SearchIndex = 0
$global:SearchIndex2 = 0
$bt_Search.Add_Click({
$SearchValue = $tb_Search.text
$dg.SelectedCells.Clear()
for ($i = $global:SearchIndex; $i -lt $dg.Items.Count; $i++)
{
$global:BreakPoint = $false
For($j=$global:SearchIndex2;$j -le 2;$j++){
If($dg.Items[$i].Row[$j] -eq "$SearchValue"){
$dg.ScrollIntoView($dg.Items[$i],$dg.Columns[$j])
$DGCell = $dg.Columns[$j].GetCellContent($dg.Items[$i]).Parent
$DGCellInfo = New-Object System.Windows.Controls.DataGridCellInfo($DGCell)
$dg.SelectedCells.add($DGCellInfo)
$global:SearchIndex = $i
$global:SearchIndex2 = $j+1
$global:BreakPoint = $true
break
}
}
If($global:BreakPoint){break}
$global:SearchIndex2=0
}
#check if we hit the end of the table. If we did display a notice and reset the search index.
If($global:SearchIndex -ge $dg.Items.Count){
[System.Windows.Forms.MessageBox]::Show("No more matches found, resetting search to begining of table.")
$global:SearchIndex=0
$global:SearchIndex2=0
}
})