5
5
using System ;
6
6
using System . Collections . Generic ;
7
7
using System . Reflection ;
8
+ using Microsoft . Toolkit . Uwp . UI . Extensions . Tree ;
8
9
using Windows . UI . Xaml ;
9
10
using Windows . UI . Xaml . Controls ;
10
11
using Windows . UI . Xaml . Markup ;
@@ -27,10 +28,9 @@ public static class LogicalTree
27
28
/// <returns>The child that was found, or <see langword="null"/>.</returns>
28
29
public static FrameworkElement ? FindChild ( this FrameworkElement element , string name , StringComparison comparisonType = StringComparison . Ordinal )
29
30
{
30
- return FindChild < FrameworkElement , ( string Name , StringComparison ComparisonType ) > (
31
- element ,
32
- ( name , comparisonType ) ,
33
- static ( e , s ) => s . Name . Equals ( e . Name , s . ComparisonType ) ) ;
31
+ PredicateByName predicateByName = new ( name , comparisonType ) ;
32
+
33
+ return FindChild < FrameworkElement , PredicateByName > ( element , ref predicateByName ) ;
34
34
}
35
35
36
36
/// <summary>
@@ -42,7 +42,9 @@ public static class LogicalTree
42
42
public static T ? FindChild < T > ( this FrameworkElement element )
43
43
where T : notnull , FrameworkElement
44
44
{
45
- return FindChild < T > ( element , static _ => true ) ;
45
+ PredicateByAny < T > predicateByAny = default ;
46
+
47
+ return FindChild < T , PredicateByAny < T > > ( element , ref predicateByAny ) ;
46
48
}
47
49
48
50
/// <summary>
@@ -53,7 +55,9 @@ public static class LogicalTree
53
55
/// <returns>The child that was found, or <see langword="null"/>.</returns>
54
56
public static FrameworkElement ? FindChild ( this FrameworkElement element , Type type )
55
57
{
56
- return FindChild < FrameworkElement , Type > ( element , type , static ( e , t ) => e . GetType ( ) == t ) ;
58
+ PredicateByType predicateByType = new ( type ) ;
59
+
60
+ return FindChild < FrameworkElement , PredicateByType > ( element , ref predicateByType ) ;
57
61
}
58
62
59
63
/// <summary>
@@ -66,97 +70,9 @@ public static class LogicalTree
66
70
public static T ? FindChild < T > ( this FrameworkElement element , Func < T , bool > predicate )
67
71
where T : notnull , FrameworkElement
68
72
{
69
- if ( element is Panel panel )
70
- {
71
- foreach ( UIElement child in panel . Children )
72
- {
73
- if ( child is not FrameworkElement current )
74
- {
75
- continue ;
76
- }
77
-
78
- if ( child is T result && predicate ( result ) )
79
- {
80
- return result ;
81
- }
82
-
83
- T ? descendant = FindChild ( current , predicate ) ;
84
-
85
- if ( descendant is not null )
86
- {
87
- return descendant ;
88
- }
89
- }
90
- }
91
- else if ( element is ItemsControl itemsControl )
92
- {
93
- foreach ( object item in itemsControl . Items )
94
- {
95
- if ( item is not FrameworkElement current )
96
- {
97
- continue ;
98
- }
99
-
100
- if ( item is T result && predicate ( result ) )
101
- {
102
- return result ;
103
- }
104
-
105
- T ? descendant = FindChild ( current , predicate ) ;
73
+ PredicateByFunc < T > predicateByFunc = new ( predicate ) ;
106
74
107
- if ( descendant is not null )
108
- {
109
- return descendant ;
110
- }
111
- }
112
- }
113
- else if ( element is UserControl userControl )
114
- {
115
- if ( userControl . Content is T result && predicate ( result ) )
116
- {
117
- return result ;
118
- }
119
-
120
- if ( userControl . Content is FrameworkElement content )
121
- {
122
- return FindChild ( content , predicate ) ;
123
- }
124
- }
125
- else if ( element is ContentControl contentControl )
126
- {
127
- if ( contentControl . Content is T result && predicate ( result ) )
128
- {
129
- return result ;
130
- }
131
-
132
- if ( contentControl . Content is FrameworkElement content )
133
- {
134
- return FindChild ( content , predicate ) ;
135
- }
136
- }
137
- else if ( element is Border border )
138
- {
139
- if ( border . Child is T result && predicate ( result ) )
140
- {
141
- return result ;
142
- }
143
-
144
- if ( border . Child is FrameworkElement child )
145
- {
146
- return FindChild ( child , predicate ) ;
147
- }
148
- }
149
- else if ( element . GetContentControl ( ) is FrameworkElement containedControl )
150
- {
151
- if ( containedControl is T result && predicate ( result ) )
152
- {
153
- return result ;
154
- }
155
-
156
- return FindChild ( containedControl , predicate ) ;
157
- }
158
-
159
- return null ;
75
+ return FindChild < T , PredicateByFunc < T > > ( element , ref predicateByFunc ) ;
160
76
}
161
77
162
78
/// <summary>
@@ -170,6 +86,23 @@ public static class LogicalTree
170
86
/// <returns>The child that was found, or <see langword="null"/>.</returns>
171
87
public static T ? FindChild < T , TState > ( this FrameworkElement element , TState state , Func < T , TState , bool > predicate )
172
88
where T : notnull , FrameworkElement
89
+ {
90
+ PredicateByFunc < T , TState > predicateByFunc = new ( state , predicate ) ;
91
+
92
+ return FindChild < T , PredicateByFunc < T , TState > > ( element , ref predicateByFunc ) ;
93
+ }
94
+
95
+ /// <summary>
96
+ /// Find the first child element matching a given predicate, using a depth-first search.
97
+ /// </summary>
98
+ /// <typeparam name="T">The type of elements to match.</typeparam>
99
+ /// <typeparam name="TPredicate">The type of predicate in use.</typeparam>
100
+ /// <param name="element">The root element.</param>
101
+ /// <param name="predicate">The predicatee to use to match the child nodes.</param>
102
+ /// <returns>The child that was found, or <see langword="null"/>.</returns>
103
+ private static T ? FindChild < T , TPredicate > ( this FrameworkElement element , ref TPredicate predicate )
104
+ where T : notnull , FrameworkElement
105
+ where TPredicate : struct , IPredicate < T >
173
106
{
174
107
if ( element is Panel panel )
175
108
{
@@ -180,12 +113,12 @@ public static class LogicalTree
180
113
continue ;
181
114
}
182
115
183
- if ( child is T result && predicate ( result , state ) )
116
+ if ( child is T result && predicate . Match ( result ) )
184
117
{
185
118
return result ;
186
119
}
187
120
188
- T ? descendant = FindChild ( current , state , predicate ) ;
121
+ T ? descendant = FindChild < T , TPredicate > ( current , ref predicate ) ;
189
122
190
123
if ( descendant is not null )
191
124
{
@@ -202,12 +135,12 @@ public static class LogicalTree
202
135
continue ;
203
136
}
204
137
205
- if ( item is T result && predicate ( result , state ) )
138
+ if ( item is T result && predicate . Match ( result ) )
206
139
{
207
140
return result ;
208
141
}
209
142
210
- T ? descendant = FindChild ( current , state , predicate ) ;
143
+ T ? descendant = FindChild < T , TPredicate > ( current , ref predicate ) ;
211
144
212
145
if ( descendant is not null )
213
146
{
@@ -217,48 +150,48 @@ public static class LogicalTree
217
150
}
218
151
else if ( element is UserControl userControl )
219
152
{
220
- if ( userControl . Content is T result && predicate ( result , state ) )
153
+ if ( userControl . Content is T result && predicate . Match ( result ) )
221
154
{
222
155
return result ;
223
156
}
224
157
225
158
if ( userControl . Content is FrameworkElement content )
226
159
{
227
- return FindChild ( content , state , predicate ) ;
160
+ return FindChild < T , TPredicate > ( content , ref predicate ) ;
228
161
}
229
162
}
230
163
else if ( element is ContentControl contentControl )
231
164
{
232
- if ( contentControl . Content is T result && predicate ( result , state ) )
165
+ if ( contentControl . Content is T result && predicate . Match ( result ) )
233
166
{
234
167
return result ;
235
168
}
236
169
237
170
if ( contentControl . Content is FrameworkElement content )
238
171
{
239
- return FindChild ( content , state , predicate ) ;
172
+ return FindChild < T , TPredicate > ( content , ref predicate ) ;
240
173
}
241
174
}
242
175
else if ( element is Border border )
243
176
{
244
- if ( border . Child is T result && predicate ( result , state ) )
177
+ if ( border . Child is T result && predicate . Match ( result ) )
245
178
{
246
179
return result ;
247
180
}
248
181
249
182
if ( border . Child is FrameworkElement child )
250
183
{
251
- return FindChild ( child , state , predicate ) ;
184
+ return FindChild < T , TPredicate > ( child , ref predicate ) ;
252
185
}
253
186
}
254
187
else if ( element . GetContentControl ( ) is FrameworkElement containedControl )
255
188
{
256
- if ( containedControl is T result && predicate ( result , state ) )
189
+ if ( containedControl is T result && predicate . Match ( result ) )
257
190
{
258
191
return result ;
259
192
}
260
193
261
- return FindChild ( containedControl , state , predicate ) ;
194
+ return FindChild < T , TPredicate > ( containedControl , ref predicate ) ;
262
195
}
263
196
264
197
return null ;
@@ -456,10 +389,9 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
456
389
/// <returns>The parent that was found, or <see langword="null"/>.</returns>
457
390
public static FrameworkElement ? FindParent ( this FrameworkElement element , string name , StringComparison comparisonType = StringComparison . Ordinal )
458
391
{
459
- return FindParent < FrameworkElement , ( string Name , StringComparison ComparisonType ) > (
460
- element ,
461
- ( name , comparisonType ) ,
462
- static ( e , s ) => s . Name . Equals ( e . Name , s . ComparisonType ) ) ;
392
+ PredicateByName predicateByName = new ( name , comparisonType ) ;
393
+
394
+ return FindParent < FrameworkElement , PredicateByName > ( element , ref predicateByName ) ;
463
395
}
464
396
465
397
/// <summary>
@@ -471,20 +403,9 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
471
403
public static T ? FindParent < T > ( this FrameworkElement element )
472
404
where T : notnull , FrameworkElement
473
405
{
474
- while ( true )
475
- {
476
- if ( element . Parent is not FrameworkElement parent )
477
- {
478
- return null ;
479
- }
480
-
481
- if ( parent is T result )
482
- {
483
- return result ;
484
- }
406
+ PredicateByAny < T > predicateByAny = default ;
485
407
486
- element = parent ;
487
- }
408
+ return FindParent < T , PredicateByAny < T > > ( element , ref predicateByAny ) ;
488
409
}
489
410
490
411
/// <summary>
@@ -495,7 +416,9 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
495
416
/// <returns>The parent that was found, or <see langword="null"/>.</returns>
496
417
public static FrameworkElement ? FindParent ( this FrameworkElement element , Type type )
497
418
{
498
- return FindParent < FrameworkElement , Type > ( element , type , static ( e , t ) => e . GetType ( ) == t ) ;
419
+ PredicateByType predicateByType = new ( type ) ;
420
+
421
+ return FindParent < FrameworkElement , PredicateByType > ( element , ref predicateByType ) ;
499
422
}
500
423
501
424
/// <summary>
@@ -508,20 +431,9 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
508
431
public static T ? FindParent < T > ( this FrameworkElement element , Func < T , bool > predicate )
509
432
where T : notnull , FrameworkElement
510
433
{
511
- while ( true )
512
- {
513
- if ( element . Parent is not FrameworkElement parent )
514
- {
515
- return null ;
516
- }
517
-
518
- if ( parent is T result && predicate ( result ) )
519
- {
520
- return result ;
521
- }
434
+ PredicateByFunc < T > predicateByFunc = new ( predicate ) ;
522
435
523
- element = parent ;
524
- }
436
+ return FindParent < T , PredicateByFunc < T > > ( element , ref predicateByFunc ) ;
525
437
}
526
438
527
439
/// <summary>
@@ -535,6 +447,23 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
535
447
/// <returns>The parent that was found, or <see langword="null"/>.</returns>
536
448
public static T ? FindParent < T , TState > ( this FrameworkElement element , TState state , Func < T , TState , bool > predicate )
537
449
where T : notnull , FrameworkElement
450
+ {
451
+ PredicateByFunc < T , TState > predicateByFunc = new ( state , predicate ) ;
452
+
453
+ return FindParent < T , PredicateByFunc < T , TState > > ( element , ref predicateByFunc ) ;
454
+ }
455
+
456
+ /// <summary>
457
+ /// Find the first parent element matching a given predicate.
458
+ /// </summary>
459
+ /// <typeparam name="T">The type of elements to match.</typeparam>
460
+ /// <typeparam name="TPredicate">The type of predicate in use.</typeparam>
461
+ /// <param name="element">The starting element.</param>
462
+ /// <param name="predicate">The predicatee to use to match the parent nodes.</param>
463
+ /// <returns>The parent that was found, or <see langword="null"/>.</returns>
464
+ private static T ? FindParent < T , TPredicate > ( this FrameworkElement element , ref TPredicate predicate )
465
+ where T : notnull , FrameworkElement
466
+ where TPredicate : struct , IPredicate < T >
538
467
{
539
468
while ( true )
540
469
{
@@ -543,7 +472,7 @@ public static IEnumerable<FrameworkElement> FindChildren(this FrameworkElement e
543
472
return null ;
544
473
}
545
474
546
- if ( parent is T result && predicate ( result , state ) )
475
+ if ( parent is T result && predicate . Match ( result ) )
547
476
{
548
477
return result ;
549
478
}
0 commit comments