Reputation: 307
Brand new to WPF, pretty comfortable with WinForms (which is probably making the transition rougher). I'm trying to port some functionality from an old WinForms project into WPF as a learning experience.
The goal is to find cell values in a DataGrid matching a string in a TextBox. I found a great example using bindings that will do exactly that. Basically the linked code will change the background color of any matching DataGridCell to orange. I've modified my version a bit, but the functionality should be the same. Please see the link for code examples, seems a bit redundant to provide it here. The data populating my DataGrid is a from a DataTable (if that matters).
What I want to do from there is have a "next" button that will cycle through each of those cells (determined by either using the background color or the custom property DataGridTextSearch.IsTextMatch) and select it. Seems like it would be possible to just modify the provided code some, but I don't know where to begin. In my old WinForms project I stored the DataGridViewCell in a list (after finding them with a Linq query) and just attached the button behavior to incrementing said list and setting the current cell. I suspect there's probably a smarter/better way involving bindings, and I don't even know how to add these matching cells to a list if that were an option.
So, to summarize, I want a button that cycles through specific DataGridCells (based on the Background or the custom DataGridTextSearch.IsTextMatch property) and selects them.
Thanks in advance.
Upvotes: 5
Views: 376
Reputation: 4808
Based on the link you provided in your question, I've come to a solution for this. In my solution when a DataGridCell
matches the string in the TextBox
, it's Tag
property will be set to "1" and then when the Button
gets clicked, it'll iterate through all DataGridCells
and find items with non-null Tags
and finally highlighted cells will be focused one by one.
Here is a working example to give you an idea:
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++;
}
Methods to get highlighted cells:
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;
}
Upvotes: 5