26

Using the code I can get a content presenter. I would like to locate the first textbox inside it and set the focus accordingly.

Dim obj = TerritoryListViewer.ItemContainerGenerator.ContainerFromItem(myModel)
GEEF
  • 1,175
  • 5
  • 17
Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447

4 Answers4

31

You can use VisualTreeHelper static class to crawl controls tree. This is how it can be accomplished in c# (sorry I'm VB dyslexic))

 T FindFirstChild<T>(FrameworkElement element) where T: FrameworkElement
    {
        int childrenCount = VisualTreeHelper.GetChildrenCount(element);
        var children = new FrameworkElement[childrenCount];

        for (int i = 0; i < childrenCount; i++)
        {
            var child = VisualTreeHelper.GetChild(element, i) as FrameworkElement;
            children[i] = child;
            if (child is T)
                return (T)child;
        }

        for (int i = 0; i < childrenCount; i++)
            if (children[i] != null)
            {
                var subChild = FindFirstChild<T>(children[i]);
                if (subChild != null)
                    return subChild;
            }

        return null;
    }
alpha-mouse
  • 4,953
  • 24
  • 36
  • 3
    This works for most Framework elememnts, but does not work for me with ContentPresenter – John Melville Mar 03 '12 at 02:18
  • 2
    @John: sounds strange. So what's the problem exactly? Are you unable to find ContentPresenter in the tree, or find child of ContentPresenter? Could it be that when you are searching visual tree is not constructed yet? – alpha-mouse Mar 05 '12 at 11:50
  • 2
    @ Alpha-mouse: You got it! I wass adding an element to the list and then immediately trying to focus one of its controls. Using the dispatcher to schedule the focus operation to background priority fixed my problem. – John Melville Mar 07 '12 at 04:54
  • Add public static in front of the T on the first line to make it compile, then it worked for me. – Chris Arbogast May 12 '22 at 23:15
19

ContentPresenter has the only child. You get the child simply by

VisualTreeHelper.GetChild(yourContentPresenterObj, 0);

If you need to go deeper - down to a first found TextBox, then, yes, you use the more comprehensive approach suggested by @alpha-mouse.

epox
  • 9,236
  • 1
  • 55
  • 38
3
Dim myContentPresenter = CType(obj, ContentPresenter)
Dim myDataTemplate = myContentPresenter.ContentTemplate
Dim target = CType(myDataTemplate.FindName("txtQuantity", myContentPresenter), TextBox)
Scott Whitlock
  • 13,739
  • 7
  • 65
  • 114
Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447
0

In my case I needed to iterate on all controls of a certain base type placed on a custom canvas which was being used inside an ItemsControl.

This Linq expression was used to get those controls from within MeasureOverride():

var foobarControls =
    InternalChildren
    .OfType<ContentPresenter>()
    .Where(c => VisualTreeHelper.GetChildrenCount(c) > 0)
    .Select(c => VisualTreeHelper.GetChild(c, 0))
    .OfType<FoobarControlBase>();

This guards against cases where the ContentPresenter had no children. I found in some instances depending on when this was called the visual tree might not be established and as a result the ContentPresenters would have no children. (This situation might have been a bug in itself, actually, but nonetheless this code turned out to be reliable.)

StayOnTarget
  • 11,743
  • 10
  • 52
  • 81