@@ -31,7 +31,7 @@ public int PageSize
3131
3232 private readonly Dictionary < string , Func < T , bool > > _filters = [ ] ;
3333 private readonly List < ( Func < T , object > selector , bool ascending ) > _sorts = [ ] ;
34- private Func < T , string > ? _searchSelector ;
34+ private IEnumerable < Func < T , string > > _searchSelectors = [ ] ;
3535 private string ? _searchTerm ;
3636 private bool _useWildcards ;
3737 private System . Threading . Timer ? _debounceTimer ;
@@ -164,7 +164,49 @@ public void ClearFilters()
164164 /// <param name="debounceMilliseconds">Optional. The number of milliseconds to debounce the search. If 0, no debouncing occurs.</param>
165165 public void SetSearch ( Func < T , string > selector , string ? term , bool useWildcards = false , int debounceMilliseconds = 0 )
166166 {
167- _searchSelector = selector ;
167+ SetSearch ( [ selector ] , term , useWildcards , debounceMilliseconds ) ;
168+ }
169+
170+ /// <summary>
171+ /// Sets the search criteria for the collection, searching across multiple properties.
172+ /// </summary>
173+ /// <param name="selectors">A collection of functions that return the string representation of the properties to search.</param>
174+ /// <param name="term">The search term.</param>
175+ /// <param name="useWildcards">A value indicating whether to use wildcards in the search term.</param>
176+ /// <param name="debounceMilliseconds">Optional. The number of milliseconds to debounce the search. If 0, no debouncing occurs.</param>
177+ public void SetSearch ( IEnumerable < Func < T , string > > selectors , string ? term , bool useWildcards = false , int debounceMilliseconds = 0 )
178+ {
179+ _searchSelectors = selectors ?? throw new ArgumentNullException ( nameof ( selectors ) ) ;
180+ _searchTerm = term ;
181+ _useWildcards = useWildcards ;
182+
183+ if ( debounceMilliseconds > 0 )
184+ {
185+ IsSearching = true ;
186+ _debounceTimer ? . Dispose ( ) ;
187+ _debounceTimer = new System . Threading . Timer ( _ =>
188+ {
189+ System . Windows . Application . Current . Dispatcher . Invoke ( ApplyFiltering ) ;
190+ IsSearching = false ;
191+ } , null , debounceMilliseconds , System . Threading . Timeout . Infinite ) ;
192+ }
193+ else
194+ {
195+ ApplyFiltering ( ) ;
196+ SearchChanged ? . Invoke ( this , EventArgs . Empty ) ;
197+ }
198+ }
199+
200+ /// <summary>
201+ /// Sets the search criteria for the collection, requiring all selectors to match the term.
202+ /// </summary>
203+ /// <param name="selectors">A collection of functions that return the string representation of the properties to search.</param>
204+ /// <param name="term">The search term.</param>
205+ /// <param name="useWildcards">A value indicating whether to use wildcards in the search term.</param>
206+ /// <param name="debounceMilliseconds">Optional. The number of milliseconds to debounce the search. If 0, no debouncing occurs.</param>
207+ public void SetSearchAll ( IEnumerable < Func < T , string > > selectors , string ? term , bool useWildcards = false , int debounceMilliseconds = 0 )
208+ {
209+ _searchSelectors = selectors ?? throw new ArgumentNullException ( nameof ( selectors ) ) ;
168210 _searchTerm = term ;
169211 _useWildcards = useWildcards ;
170212
@@ -190,7 +232,7 @@ public void SetSearch(Func<T, string> selector, string? term, bool useWildcards
190232 /// </summary>
191233 public void ClearSearch ( )
192234 {
193- _searchSelector = null ;
235+ _searchSelectors = [ ] ;
194236 _searchTerm = null ;
195237 _useWildcards = false ;
196238 ApplyFiltering ( ) ;
@@ -230,19 +272,23 @@ private void ApplyFiltering()
230272 query = query . Where ( filter ) ;
231273 }
232274
233- if ( ! string . IsNullOrWhiteSpace ( _searchTerm ) && _searchSelector != null )
275+ if ( ! string . IsNullOrWhiteSpace ( _searchTerm ) && _searchSelectors . Any ( ) )
234276 {
277+ var term = _searchTerm ;
278+ Func < string , bool > matches ;
279+
235280 if ( _useWildcards )
236281 {
237- var regex = new Regex ( WildcardToRegex ( _searchTerm ) , RegexOptions . IgnoreCase ) ;
238- query = query . Where ( x => regex . IsMatch ( _searchSelector ( x ) ) ) ;
282+ var regex = new Regex ( WildcardToRegex ( term ) , RegexOptions . IgnoreCase ) ;
283+ matches = s => regex . IsMatch ( s ) ;
239284 }
240285 else
241286 {
242- query = query . Where ( x =>
243- _searchSelector ( x )
244- ? . Contains ( _searchTerm , StringComparison . OrdinalIgnoreCase ) == true ) ;
287+ matches = s => s . Contains ( term , StringComparison . OrdinalIgnoreCase ) ;
245288 }
289+
290+ // OR logic for multi-column search
291+ query = query . Where ( item => _searchSelectors . Any ( selector => matches ( selector ( item ) ?? string . Empty ) ) ) ;
246292 }
247293
248294 if ( _sorts . Count > 0 )
0 commit comments