Asked by:
Visual Tree Helper

Question
-
User45549 posted
Hi,
Is there an equivalent of WPF's VisualTreeHelper? I need to loop through all the visual elements of a page.
Thank you
Tuesday, June 17, 2014 4:53 AM
All replies
-
User127380 posted
Hello, I am interested in this as well. My situation is the opposite from Heinrich's: I need to access a Page element at an arbitrary distance up the visual tree.
Thank you.
Tuesday, May 12, 2015 5:08 PM -
User112992 posted
Bump. Or alternatively, anyone have a good algorithm for searching a Contentpage for all elements of a certain type (eg. Entry)?
Friday, May 15, 2015 9:21 PM -
User147638 posted
I'm after this too :(
Friday, October 2, 2015 9:53 AM -
User64349 posted
bump
Sunday, October 4, 2015 4:24 PM -
User138971 posted
also interested...xamarin developers!
Tuesday, January 12, 2016 1:33 PM -
User56686 posted
I would also need this functionality. I would even be satisfied if container elements like ListView, StackLayout,... shared a simple interface like
IChildrenContainer
interface which exposes its children.It seems all you can do now is to listen at the top container (App?) for
DescendantAdded
andDescendantRemoved
and roll your own DOM.@BryanHunterXam It would be nice if a Xamarin team-member would describe their current viewpoint on the topic here.
Tuesday, April 19, 2016 6:10 AM -
User211464 posted
Hi, my solution, Good luck !
public static List<T> FindVisualChildren<T>(this VisualElement parentElement, VisualElement whereSearch, string containsStringName = null, List<T> result = null) { result = result ?? new List<T>(); try { var props = whereSearch.GetType().GetRuntimeProperties(); var contProp = props.FirstOrDefault(w => w.Name == "Content"); var childProp = props.FirstOrDefault(w => w.Name == "Children"); if (childProp == null) { if (contProp != null) { var cv = contProp.GetValue(whereSearch) as VisualElement; if (cv != null) FindVisualChildren<T>(parentElement, cv, containsStringName, result); } return result; } IEnumerable v = childProp.GetValue(whereSearch) as IEnumerable; foreach (var i in v) { if (i is VisualElement) FindVisualChildren<T>(parentElement, i as VisualElement, containsStringName, result); if (i is T) { if (!string.IsNullOrEmpty(containsStringName)) { bool fCheck = false; var fields = parentElement.GetType().GetRuntimeFields().Where(w => w.Name.ToLower().Contains(containsStringName.ToLower())).ToList(); foreach(var f in fields) { var fv = f.GetValue(parentElement); if (fv is T && fv == i) { fCheck = true; break; } } if (!fCheck) continue; } var ii = (T)i; result.Add(ii); } } return result; } catch { return result; } }
Thursday, June 9, 2016 10:48 AM -
User138971 posted
great job, it works like a charm! :-)
Wednesday, July 20, 2016 10:12 AM -
User138971 posted
it's so strange. I noticed that if I put an image inside a button, in this way:
<Grid> <Button> <Image Source="image.png" VerticalOptions="End" HorizontalOptions="Start"></Image> </Button> </Grid>
with this function I can't retrieve it, so it's not added to the list returned. Looking inside the button with the debugger I can't find any reference to the image, because it has no children or content. So, how can I do to retrieve it from the button? I would be sure that the FindVisualChildren function collect all the controls that I'm looking for.
Thursday, July 21, 2016 10:31 AM -
User211464 posted
I think it's not a good idea to use a button as a container ... I recommend to use iconic font - it's just super! But there are situations in principle, if you do this, I take the time to decide this question ...
Thursday, August 4, 2016 10:30 PM -
User248484 posted
@TDennis thanks for sharing, but lemme share a few comments about your code, I haven't checked the code or ran it, but looking at it. To emphasize, this is a shallow look over, not even a recommendation. I might be wrong.
- Why the
try
block? Should be avoided IMHO. - Why not using an iterator so it's all lazily evaluated?
- You should get the
Children
property only if theContent
one isnull
. - You could replace getting those properties by reflection by determining if it's
View
orLayout
etc. - Why have the
containsStringName
, allowing partial names? Anyway, use index search ignoring case instead of lowering both strings.
Wednesday, July 5, 2017 4:20 AM - Why the
-
User30998 posted
@TDenis -- nice, but does not work for ListView. I've been searching high and low, seems to be next to impossible to find via the debugger, reflection, or anything else.
Sunday, September 24, 2017 12:58 AM -
User211464 posted
@ShimmyWeitzhandler - all comments are appropriate, you can apply them to your code, in my situation this was a good decision for me, and since I did not find anything like that I decided to share it with them.
@WilliamJockusch - Here, caching strategies are used, it probably will not be easy, but I'll try, if I find a solution, I'll write
Sunday, September 24, 2017 10:23 AM -
User30998 posted
@TDenis thanks -- it's not obligatory; I found a work-around for my situation. Would still be interesting if there is a way.
Sunday, September 24, 2017 4:04 PM -
User248484 posted
@TDenis Thanks for sharing anyway! Really appreciated! :love:
Monday, September 25, 2017 1:37 AM -
User67215 posted
Modified for ListView:
public static List<T> FindVisualChildren<T>(this VisualElement parentElement, VisualElement whereSearch, string containsStringName = null, List<T> result = null) { result = result ?? new List<T>(); try { var props = whereSearch.GetType().GetRuntimeProperties(); var contProp = props.FirstOrDefault(w => w.Name == "Content"); var childProp = props.FirstOrDefault(w => w.Name == "Children"); var itemsProp = props.FirstOrDefault(w => w.Name == "TemplatedItems"); if (childProp == null) childProp = itemsProp; if (childProp == null) { if (contProp != null) { var cv = contProp.GetValue(whereSearch) as VisualElement; if (cv != null) FindVisualChildren<T>(parentElement, cv, containsStringName, result); } return result; } IEnumerable v = childProp.GetValue(whereSearch) as IEnumerable; foreach (var x in v) { var i = x; if (i is ViewCell) i = ((ViewCell)i).View; if (i is VisualElement) FindVisualChildren<T>(parentElement, i as VisualElement, containsStringName, result); if (i is T) { if (!string.IsNullOrEmpty(containsStringName)) { bool fCheck = false; var fields = parentElement.GetType().GetRuntimeFields().Where(w => w.Name.ToLower().Contains(containsStringName.ToLower())).ToList(); foreach (var f in fields) { var fv = f.GetValue(parentElement); if (fv is T && fv == i) { fCheck = true; break; } } if (!fCheck) continue; } var ii = (T)i; result.Insert(0, ii); } } return result; } catch { return result; } }
Monday, March 19, 2018 6:40 AM