17

I have an control in WPF which has an unique Uid. How can I retrive the object by its Uid?

BenMorel
  • 34,448
  • 50
  • 182
  • 322
jose
  • 2,733
  • 4
  • 37
  • 51

4 Answers4

14

You pretty much have to do it by brute-force. Here's a helper extension method you can use:

private static UIElement FindUid(this DependencyObject parent, string uid)
{
    var count = VisualTreeHelper.GetChildrenCount(parent);
    if (count == 0) return null;

    for (int i = 0; i < count; i++)
    {
        var el = VisualTreeHelper.GetChild(parent, i) as UIElement;
        if (el == null) continue;

        if (el.Uid == uid) return el;

        el = el.FindUid(uid);
        if (el != null) return el;
    }
    return null;
}

Then you can call it like this:

var el = FindUid("someUid");
Matt Hamilton
  • 200,371
  • 61
  • 386
  • 320
  • Doesn't `GetChild(parent, N)` have the complexity of O(N) ? The foreach approach seems cleaner (and clearer) to me. – AgentFire Jun 03 '17 at 20:39
  • As [msdn](https://social.msdn.microsoft.com/Forums/en-US/9b5ff9c2-434a-4324-b896-350e995b645e/automationid-property?forum=vsautotest) states, if AutomationId is not set, WindowsAutomationFramework will default it to *Uid* if set, or to _ControlName_ if set (checked via inspect.exe). So in some cases the tooling for AutomationIds suffices. – RuNe Feb 11 '19 at 20:16
5
public static UIElement GetByUid(DependencyObject rootElement, string uid)
{
    foreach (UIElement element in LogicalTreeHelper.GetChildren(rootElement).OfType<UIElement>())
    {
        if (element.Uid == uid)
            return element;
        UIElement resultChildren = GetByUid(element, uid);
        if (resultChildren != null)
            return resultChildren;
    }
    return null;
}
pr0gg3r
  • 4,254
  • 1
  • 36
  • 27
2

This is better.

public static UIElement FindUid(this DependencyObject parent, string uid) {
    int count = VisualTreeHelper.GetChildrenCount(parent);

    for (int i = 0; i < count; i++) {
        UIElement el = VisualTreeHelper.GetChild(parent, i) as UIElement;
        if (el != null) {
            if (el.Uid == uid) { return el; }
            el = el.FindUid(uid);
        }
    }
        return null;
}
SyntaxRules
  • 2,056
  • 23
  • 32
Mike
  • 623
  • 6
  • 26
  • It cannot be better if your code does not work. Your recursion is broken. The result of `el.FindUid(uid)`, if not null, must be returned. – jchristin Sep 29 '15 at 12:50
1

An issue I had with the top answer is that it won't look inside content controls (such as user controls) for elements within their content. In order to search inside these I extended the function to look at the Content property of compatible controls.

public static UIElement FindUid(this DependencyObject parent, string uid)
{
    var count = VisualTreeHelper.GetChildrenCount(parent);

    for (int i = 0; i < count; i++)
    {
        var el = VisualTreeHelper.GetChild(parent, i) as UIElement;
        if (el == null) continue;

        if (el.Uid == uid) return el;

        el = el.FindUid(uid);
        if (el != null) return el;
    }

    if (parent is ContentControl)
    {
        UIElement content = (parent as ContentControl).Content as UIElement;
        if (content != null)
        {
            if (content.Uid == uid) return content;

            var el = content.FindUid(uid);
            if (el != null) return el;
        }
    }
    return null;
}
Wilco
  • 974
  • 8
  • 14