Knowledgebase Home Page  >  RapidFindReplace WPF
Search the Knowledge Base
How to find items in a DataGrid where virtualization is enabled.
https://keyoti.com/kb/Default.aspx?ToDo=view&questId=268&catId=69

Options

Print this page
Email this to a friend

The challenge with virtualization enabled is that there aren't actual DataGridRowItems created for all data available, so the control cannot find across all the data.  

 

To get around that limitation, the code below creates a collection of Run objects based on the data in your collection.  RapidFindReplace can search invisible Run objects, and when the user clicks the 'next' or 'previous' arrow buttons, the code will select the appropriate row.

Please note that the code below does not do 'all occurrence highlighting'.  In other words the user must click next/previous to highlight the rows.

Please press CTRL-F when the Window loads to activate the Find dialog.


XAML

<Window x:Class="SearchVisualTree.DataGrid_Virtualization"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:RapidFindReplace="clr-namespace:Keyoti.RapidFindReplace.WPF;assembly=Keyoti4.RapidFindReplace.WPF" xmlns:local="clr-namespace:SearchVisualTree" 
        
        
        Title="DataGrid_Virtualization" Height="547.687" Width="468.683">
    <Grid>
        <RapidFindReplace:RapidFindReplacePopupControl HorizontalAlignment="Left" Height="0"  VerticalAlignment="Top" Width="0" Name="Finder"/>
        <DataGrid HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Height="498" Width="441" Name="dataGrid"  >

        </DataGrid>
    </Grid>
</Window>


CODEBEHIND
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace SearchVisualTree
{
    /// <summary>
    /// Interaction logic for DataGrid_Virtualization.xaml
    /// </summary>
    public partial class DataGrid_Virtualization : Window
    {
        Customers customers;
        public DataGrid_Virtualization()
        {
            InitializeComponent();
            //create data
            customers = new Customers();
            customers.Add(new Customer() { FirstName = "Andy" });
            customers.Add(new Customer() { FirstName = "Bob" });
            customers.Add(new Customer() { FirstName = "Caroline" });
            customers.Add(new Customer() { FirstName = "Dennis" });
            customers.Add(new Customer() { FirstName = "Emma" });
            customers.Add(new Customer() { FirstName = "Fred" });
            customers.Add(new Customer() { FirstName = "Georgia" });
            customers.Add(new Customer() { FirstName = "Hannah" });
            customers.Add(new Customer() { FirstName = "Ian" });
            customers.Add(new Customer() { FirstName = "Jen" });
            customers.Add(new Customer() { FirstName = "Kevin" });
            customers.Add(new Customer() { FirstName = "Louise" });
            customers.Add(new Customer() { FirstName = "Marcus" });
            customers.Add(new Customer() { FirstName = "Nora" });
            customers.Add(new Customer() { FirstName = "Oliver" });
            customers.Add(new Customer() { FirstName = "Patsy" });
            customers.Add(new Customer() { FirstName = "Quentin" });
            customers.Add(new Customer() { FirstName = "Rachael" });
            customers.Add(new Customer() { FirstName = "Steve" });
            customers.Add(new Customer() { FirstName = "Terri" });
            customers.Add(new Customer() { FirstName = "Andy" });
            customers.Add(new Customer() { FirstName = "Bob" });
            customers.Add(new Customer() { FirstName = "Caroline" });
            customers.Add(new Customer() { FirstName = "Dennis" });
            customers.Add(new Customer() { FirstName = "Emma" });
            customers.Add(new Customer() { FirstName = "Fred" });
            customers.Add(new Customer() { FirstName = "Georgia" });
            customers.Add(new Customer() { FirstName = "Hannah" });
            customers.Add(new Customer() { FirstName = "Ian" });
            customers.Add(new Customer() { FirstName = "Jen" });
            customers.Add(new Customer() { FirstName = "Kevin" });
            customers.Add(new Customer() { FirstName = "Louise" });
            customers.Add(new Customer() { FirstName = "Marcus" });
            customers.Add(new Customer() { FirstName = "Nora" });
            customers.Add(new Customer() { FirstName = "Oliver" });
            customers.Add(new Customer() { FirstName = "Patsy" });
            customers.Add(new Customer() { FirstName = "Quentin" });
            customers.Add(new Customer() { FirstName = "Rachael" });
            customers.Add(new Customer() { FirstName = "Steve" });
            customers.Add(new Customer() { FirstName = "Terri" });

            //bind data
            Binding bind = new Binding();
            bind.Source = customers;
            dataGrid.SetBinding(DataGrid.ItemsSourceProperty, bind);



            //create a Run collection of grid data, this will be searched instead of visual controls.
            List<Run> runs = new List<Run>();
            foreach (Customer customer in customers)
            {
                runs.Add(new EntityRun<Customer>(customer, customer.FirstName));
            }

            //create a 'findable' container
            Keyoti.RapidFindReplace.WPF.FindHandlers.RunCollectionContainer container = new Keyoti.RapidFindReplace.WPF.FindHandlers.RunCollectionContainer(runs);
            //setup the container as what to search within
            Finder.FindScope = container;

            //Listen to changes to the "CurrentMatch" property, when these changes occur we need to select and scroll to the CurrentMatch in the grid.
            System.ComponentModel.DependencyPropertyDescriptor dpd = System.ComponentModel.DependencyPropertyDescriptor.FromProperty
                                        (Keyoti.RapidFindReplace.WPF.RapidFindReplacePopupControl.CurrentMatchProperty, typeof(Keyoti.RapidFindReplace.WPF.RapidFindReplacePopupControl));
            dpd.AddValueChanged(Finder, new EventHandler(delegate(object sender2, EventArgs e2)
                {
                    //If there is a match, select it and scroll to it.
                    if ((sender2 as Keyoti.RapidFindReplace.WPF.RapidFindReplacePopupControl).CurrentMatch != null)
                    {
                        dataGrid.SelectedItem = (((sender2 as Keyoti.RapidFindReplace.WPF.RapidFindReplacePopupControl).CurrentMatch.Run as EntityRun<Customer>).Entity);
                        dataGrid.ScrollIntoView(dataGrid.SelectedItem);
                    }

                }));


            Loaded += delegate
            {
                Finder.PART_RapidFindReplaceControl.FinishedSearching += delegate
                {
                    MessageBox.Show(this, "No more matches");
                };
            };


        }


        public class Customers : System.Collections.ObjectModel.ObservableCollection<Customer>
        {

        }

        public class Customer
        {
            public string FirstName { get; set; }

        }

        class EntityRun<T> : Run
        {
            T entity;

            public T Entity
            {
                get { return entity; }
            }
            public EntityRun(T c, string toSearch)
                : base(toSearch)
            {
                entity = c;
            }

        }
    }
}



In this example the entity is type Customer, this can be easily modified to your class.  You will see the use of the generic type EntityRun<Customer>, just change it to your type, eg EntityRun<MyEntity>


Related Questions:

No related questions were found.
 
Attachments:

No attachments were found.