WPF数据循环通过/选择具有特定属性的单元格

时间:2021-07-12 10:04:52

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.

全新的WPF,非常适合WinForms(这可能会使转换变得更粗糙)。我试图将一些功能从一个旧的WinForms项目移植到WPF中,作为学习经验。

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).

目标是在DataGrid中找到与文本框中的字符串匹配的单元格值。我发现了一个使用绑定的很好的例子。基本上,链接的代码将把任何匹配的DataGridCell的背景颜色更改为橙色。我已经修改了我的版本,但是功能应该是一样的。请参阅代码示例的链接,在这里提供它似乎有点多余。填充我的DataGrid的数据是来自DataTable的数据(如果有关系的话)。

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.

我想要做的是有一个“next”按钮,它将循环遍历每个单元格(通过使用背景颜色或自定义属性DataGridTextSearch.IsTextMatch确定)并选择它。似乎可以对提供的代码进行一些修改,但是我不知道从哪里开始。在我以前的WinForms项目中,我将DataGridViewCell存储在一个列表中(在使用Linq查询找到它们之后),并将按钮行为附加到递增的列表中,并设置当前单元格。我怀疑可能有一种更聪明/更好的方法涉及绑定,如果可以的话,我甚至不知道如何将这些匹配单元格添加到列表中。

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.

综上所述,我想要一个通过特定的DataGridCells(基于背景或自定义DataGridTextSearch)循环的按钮。IsTextMatch属性)并选择它们。

Thanks in advance.

提前谢谢。

1 个解决方案

#1


5  

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.

根据你在问题中提供的链接,我找到了解决方案。在我的解决方案中,当一个DataGridCell与文本框中的字符串相匹配时,它的标记属性将被设置为“1”,然后当按钮被单击时,它将遍历所有的DataGridCells,并找到带有非空标记的项,最后突出显示的单元格将逐个集中。

Here is a working example to give you an idea:

这里有一个工作示例给您一个想法:

Xaml:

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:

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;
}

#1


5  

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.

根据你在问题中提供的链接,我找到了解决方案。在我的解决方案中,当一个DataGridCell与文本框中的字符串相匹配时,它的标记属性将被设置为“1”,然后当按钮被单击时,它将遍历所有的DataGridCells,并找到带有非空标记的项,最后突出显示的单元格将逐个集中。

Here is a working example to give you an idea:

这里有一个工作示例给您一个想法:

Xaml:

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:

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;
}