Visual Tree Helper

HeinrichBreedt.8522HeinrichBreedt.8522 Heinrich BreedtUSMember

Hi,

Is there an equivalent of WPF's VisualTreeHelper? I need to loop through all the visual elements of a page.

Thank you

Posts

  • RafaelRenzRafaelRenz Rafael Renz USMember

    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.

  • JeremyHerbisonJeremyHerbison Jeremy Herbison CAMember ✭✭

    Bump. Or alternatively, anyone have a good algorithm for searching a Contentpage for all elements of a certain type (eg. Entry)?

  • PeterMillsPeterMills Peter Mills GBMember ✭✭

    I'm after this too :(

  • ReinisLusisReinisLusis Reinis Lusis LVMember

    bump

  • CaioshinCaioshin Fabio Giacomelli ITMember ✭✭

    also interested...xamarin developers!

  • David.RettenbacherDavid.Rettenbacher David Rettenbacher ATMember ✭✭

    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 and DescendantRemoved and roll your own DOM.

    @BryanHunterXam
    It would be nice if a Xamarin team-member would describe their current viewpoint on the topic here.

  • TDenisTDenis Denis Toloknov USMember ✭✭
    edited June 2016

    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; }
        }
    
  • CaioshinCaioshin Fabio Giacomelli ITMember ✭✭

    great job, it works like a charm! :-)

  • CaioshinCaioshin Fabio Giacomelli ITMember ✭✭
    edited July 2016

    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.

  • TDenisTDenis Denis Toloknov USMember ✭✭

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

  • ShimmyWeitzhandlerShimmyWeitzhandler Shimmy Weitzhandler USMember ✭✭✭
    edited July 5

    @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 the Content one is null.
    • You could replace getting those properties by reflection by determining if it's View or Layout etc.
    • Why have the containsStringName, allowing partial names? Anyway, use index search ignoring case instead of lowering both strings.
  • WilliamJockuschWilliamJockusch William Jockusch USMember ✭✭

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

  • TDenisTDenis Denis Toloknov USMember ✭✭

    @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

  • WilliamJockuschWilliamJockusch William Jockusch USMember ✭✭

    @TDenis thanks -- it's not obligatory; I found a work-around for my situation. Would still be interesting if there is a way.

  • ShimmyWeitzhandlerShimmyWeitzhandler Shimmy Weitzhandler USMember ✭✭✭

    @TDenis
    Thanks for sharing anyway! Really appreciated! :love:

Sign In or Register to comment.