WPF 数据网格循环 Through/Select 具有特定 属性 的单元格
WPF Datagrid Cycle Through/Select Cells With Specific Property
全新的 WPF,对 WinForms 非常熟悉(这可能会使过渡变得更加艰难)。我正在尝试将一些功能从旧的 WinForms 项目移植到 WPF 中,作为一种学习体验。
目标是在 DataGrid 中查找与 TextBox 中的字符串相匹配的单元格值。我找到了一个 great example using bindings 可以做到这一点。基本上,linked 代码会将任何匹配的 DataGridCell 的背景颜色更改为橙色。我对我的版本做了一些修改,但功能应该是一样的。请参阅 link 的代码示例,在这里提供它似乎有点多余。填充我的 DataGrid 的数据来自 DataTable(如果重要的话)。
我想从那里做的是有一个 "next" 按钮,它将循环浏览每个单元格(通过使用背景颜色或自定义 属性 DataGridTextSearch.IsTextMatch ) 和 select 它。似乎可以只修改提供的代码一些,但我不知道从哪里开始。在我的旧 WinForms 项目中,我将 DataGridViewCell 存储在一个列表中(在使用 Linq 查询找到它们之后),并将按钮行为附加到递增所述列表并设置当前单元格。我怀疑可能有一种涉及绑定的 smarter/better 方式,如果可以的话,我什至不知道如何将这些匹配的单元格添加到列表中。
因此,总而言之,我想要一个循环显示特定 DataGridCell(基于背景或自定义 DataGridTextSearch.IsTextMatch 属性)和 select 的按钮。
提前致谢。
根据您在问题中提供的link,我得出了解决方案。在我的解决方案中,当 DataGridCell
匹配 TextBox
中的字符串时,Tag
属性 将被设置为“1”,然后当 Button
被点击时,它将遍历所有 DataGridCells
并找到具有非空 Tags
的项目,最后突出显示的单元格将一个一个地聚焦。
这是一个可以给你一个想法的工作示例:
Xaml:
<Window Name="UI">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel DataContext="{Binding ElementName=UI}" Grid.Row="0">
<TextBox Name="SearchBox" TextChanged="SearchBox_TextChanged"/>
<DataGrid x:Name="grid"
m:DataGridTextSearch.SearchValue="{Binding ElementName=SearchBox, Path=Text, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding TestData}"
SelectionUnit="Cell">
<DataGrid.Resources>
<m:SearchValueConverter x:Key="SearchValueConverter" />
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="m:DataGridTextSearch.IsTextMatch">
<Setter.Value>
<MultiBinding Converter="{StaticResource SearchValueConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="Content.Text" />
<Binding RelativeSource="{RelativeSource Self}" Path="(m:DataGridTextSearch.SearchValue)" />
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="m:DataGridTextSearch.IsTextMatch" Value="True">
<Setter Property="Background" Value="Orange" />
<Setter Property="Tag" Value="1" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
</DataGrid>
</StackPanel>
<Button Grid.Row="1" Click="Button_Click" Content="GoNext"/>
</Grid>
</Window>
MainWindow.cs:
int currentIndex = 0;
private void SearchBox_TextChanged(object sender, TextChangedEventArgs e)
{
currentIndex = 0;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var selectedCells = GetHighLightedCells();
if (selectedCells.Count == 0)
return;
selectedCells[currentIndex].Focus();
if (currentIndex == selectedCells.Count - 1)
currentIndex = 0;
else
currentIndex++;
}
获取高亮单元格的方法:
public List<DataGridCell> GetHighLightedCells()
{
List<DataGridCell> selectedCells = new List<DataGridCell>();
foreach (DataGridRow rowContainer in GetDataGridRows())
{
if (rowContainer != null)
{
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
foreach (var col in grid.Columns)
{
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(col.DisplayIndex);
if (cell == null)
{
grid.ScrollIntoView(rowContainer, col);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(col.DisplayIndex);
}
if (cell.Tag != null)
{
selectedCells.Add(cell);
}
}
}
}
return selectedCells;
}
public IEnumerable<DataGridRow> GetDataGridRows()
{
var itemsSource = grid.ItemsSource as IEnumerable;
if (null == itemsSource) yield return null;
foreach (var item in itemsSource)
{
var row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (null != row) yield return row;
}
}
public static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
全新的 WPF,对 WinForms 非常熟悉(这可能会使过渡变得更加艰难)。我正在尝试将一些功能从旧的 WinForms 项目移植到 WPF 中,作为一种学习体验。
目标是在 DataGrid 中查找与 TextBox 中的字符串相匹配的单元格值。我找到了一个 great example using bindings 可以做到这一点。基本上,linked 代码会将任何匹配的 DataGridCell 的背景颜色更改为橙色。我对我的版本做了一些修改,但功能应该是一样的。请参阅 link 的代码示例,在这里提供它似乎有点多余。填充我的 DataGrid 的数据来自 DataTable(如果重要的话)。
我想从那里做的是有一个 "next" 按钮,它将循环浏览每个单元格(通过使用背景颜色或自定义 属性 DataGridTextSearch.IsTextMatch ) 和 select 它。似乎可以只修改提供的代码一些,但我不知道从哪里开始。在我的旧 WinForms 项目中,我将 DataGridViewCell 存储在一个列表中(在使用 Linq 查询找到它们之后),并将按钮行为附加到递增所述列表并设置当前单元格。我怀疑可能有一种涉及绑定的 smarter/better 方式,如果可以的话,我什至不知道如何将这些匹配的单元格添加到列表中。
因此,总而言之,我想要一个循环显示特定 DataGridCell(基于背景或自定义 DataGridTextSearch.IsTextMatch 属性)和 select 的按钮。
提前致谢。
根据您在问题中提供的link,我得出了解决方案。在我的解决方案中,当 DataGridCell
匹配 TextBox
中的字符串时,Tag
属性 将被设置为“1”,然后当 Button
被点击时,它将遍历所有 DataGridCells
并找到具有非空 Tags
的项目,最后突出显示的单元格将一个一个地聚焦。
这是一个可以给你一个想法的工作示例:
Xaml:
<Window Name="UI">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel DataContext="{Binding ElementName=UI}" Grid.Row="0">
<TextBox Name="SearchBox" TextChanged="SearchBox_TextChanged"/>
<DataGrid x:Name="grid"
m:DataGridTextSearch.SearchValue="{Binding ElementName=SearchBox, Path=Text, UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding TestData}"
SelectionUnit="Cell">
<DataGrid.Resources>
<m:SearchValueConverter x:Key="SearchValueConverter" />
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="m:DataGridTextSearch.IsTextMatch">
<Setter.Value>
<MultiBinding Converter="{StaticResource SearchValueConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="Content.Text" />
<Binding RelativeSource="{RelativeSource Self}" Path="(m:DataGridTextSearch.SearchValue)" />
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="m:DataGridTextSearch.IsTextMatch" Value="True">
<Setter Property="Background" Value="Orange" />
<Setter Property="Tag" Value="1" />
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
</DataGrid>
</StackPanel>
<Button Grid.Row="1" Click="Button_Click" Content="GoNext"/>
</Grid>
</Window>
MainWindow.cs:
int currentIndex = 0;
private void SearchBox_TextChanged(object sender, TextChangedEventArgs e)
{
currentIndex = 0;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var selectedCells = GetHighLightedCells();
if (selectedCells.Count == 0)
return;
selectedCells[currentIndex].Focus();
if (currentIndex == selectedCells.Count - 1)
currentIndex = 0;
else
currentIndex++;
}
获取高亮单元格的方法:
public List<DataGridCell> GetHighLightedCells()
{
List<DataGridCell> selectedCells = new List<DataGridCell>();
foreach (DataGridRow rowContainer in GetDataGridRows())
{
if (rowContainer != null)
{
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
foreach (var col in grid.Columns)
{
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(col.DisplayIndex);
if (cell == null)
{
grid.ScrollIntoView(rowContainer, col);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(col.DisplayIndex);
}
if (cell.Tag != null)
{
selectedCells.Add(cell);
}
}
}
}
return selectedCells;
}
public IEnumerable<DataGridRow> GetDataGridRows()
{
var itemsSource = grid.ItemsSource as IEnumerable;
if (null == itemsSource) yield return null;
foreach (var item in itemsSource)
{
var row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (null != row) yield return row;
}
}
public static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}