locked
FindName RRS feed

  • Question

  •  

    I have a custom control that acts like a composite control.

    Below XAML:

    Reference (A)

     

    <UserControl x:Class="ControlsTestApplication.TestScreen"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:c="...=OnKey5Client.ControlLibrary"

        Width="300" Height="300">

        <c:PPForm

            x:Name="Form"

            Width="Auto"

            Height="Auto"

            Text="Work Orders Edit">

            <c:ChildCollection>

                <c:PPToolbar

                        x:Name="tbrTest">

                    <c:ChildCollection>

                            <TextBox

                                x:Name="tbxTest"

                                Width="100" />

                            <Button

                                x:Name="btnT"

                                Width="24"

                                Height="Auto"

                                Content="T" />

                        </c:ChildCollection>

                </c:PPToolbar>

            </c:ChildCollection>

        </c:PPForm>

    </UserControl>

    Visual Studio registers that tbrTest and btnT is there.
    When you run the application, they are however null.
    Having needed a way to get a handel on the controls, I build in a temp find method on the list.

    Complete code for child collection below.

    Reference (B)

        public class ChildCollection : ObservableCollection<FrameworkElement>

        {

            public FrameworkElement FindName(String entityName)

            {

                var item =

                    from c in this

                    where c.Name == entityName               

                    select c;

     

                if (item.Count() == 0)

                    return null;

     

                return item.ElementAt(0);

            }

        };

    This means that if I want to access those controls, I now have to do this:

    Reference (C)


    _tbrTest = Form.Children.FindName("tbrTest") as PPToolbar;

    _btnT    = _tbrTest.Children.FindName("btnT") as Button;

    _tbxTest = _tbrTest.Children.FindName("tbxTest") as TextBox;

     

    The partial class already identifies these controls and declares instances for them, but the find method never finds it.


    What I want to do is be abel to allow the FindName method to find these controls so that I do not have to use the code seen in Reference (C)


    Now just as a reference, some code snippets out of the Form class (PPForm):

    Firstly, the class has a attribute:

    [ContentProperty("Children")]

    The class contains a dependancy property:

    public static readonly DependencyProperty ChildrenProperty =

        DependencyProperty.Register(

                    "Children",

                    typeof(ChildCollection),

                    typeof(PPForm),

                    new PropertyMetadata(OnChildrenPropertyChanged));


    Property Meta Data

    private static void OnChildrenPropertyChanged(

    DependencyObject sender,                                               DependencyPropertyChangedEventArgs args)

    {

        var form = (PPForm)sender;

        ChildCollection children = form.Children;

     

        foreach (FrameworkElement child in children)

            form._parentCanvas.Children.Add(child);

    }

     

    And Property

    public ChildCollection Children

    {

        get { return (ChildCollection)GetValue(ChildrenProperty); }

        set { SetValue(ChildrenProperty, value); }

    }

     

    The reason why I do this is because I want to add all the controls defined in Children to be displayed in a canvas that makes up part of a more elaborate control.

    So how do I allow FindName to these controls when they are items of the Children property?

    Wednesday, July 2, 2008 4:48 PM

All replies

  •  I am having this exact same problem. FindName will not work with whatever you set ContentProperty to. I can only get it to work by taking the objects out of my custom content container and placing them into a Panel object via Child.Add()

     Can anyone share more info on this?

    Thursday, October 30, 2008 6:17 PM
  • I wrote a elaborate search function in a static class I called control helper.
    So instead of using the standard find method, I used.

    TextBlock test = (TestBlock)ControlHelper.FindName(this, "MyTextblockName").

    What this method does is it uses the control you send in the first parameter's find method to see if t can find any thing.
    Some times it works, some times it does not.

    If it did not find anything, it treverts down the xaml tree and see if it can find it that way.

    It's ove the top, but if has never not found something:

     

        /// <summary>
        /// Control Helper is a static class that provides common functionality to help you work with controls.
        /// </summary>
        public static class ControlHelper
        {
            /// <summary>
            /// This method will try and find a named child control from a given parent.
            /// </summary>
            /// <param name="objectElement">Parent object to start searching in</param>
            /// <param name="controlName">The name of the control you want to find</param>
            /// <returns>Result of the find. If a object is found, the result will be that object else it will be null</returns>
            public static FrameworkElement FindName(FrameworkElement objectElement, string controlName)
            {
                // First try and find the control the normal way.
                FrameworkElement result = (FrameworkElement) objectElement.FindName(controlName);
                if (result != null)
                {
                    return result;
                }
    
                /* See if there is a children property and if so go throught hat to see if you can 
                 * find the control.
                 */
                PropertyInfo childrenProperty = objectElement.GetType().GetProperty("Children");
                if (childrenProperty != null)
                {
                    IList childrenObject = (IList) childrenProperty.GetValue(objectElement, null);
    
                    for (var i = 0; i < childrenObject.Count; i++)
                    {
                        result = (FrameworkElement) childrenObjectIdea;
                        if (result.Name == controlName)
                        {
                            return result;
                        }
    
                        // Dig recursive into the control
                        result = FindName(result, controlName);
                        if (result != null)
                        {
                            return result;
                        }
                    }
                }
    
                /* Child property does not exist or object could not be found.
                 * Go throught the xaml and see if you can find it on a xaml content level.
                 * This is recursive so to ensure you go through all the object to find the one you want.
                 */
                int childCount = VisualTreeHelper.GetChildrenCount(objectElement);
    
                for (var i = 0; i < childCount; i++)
                {
                    result = (FrameworkElement) VisualTreeHelper.GetChild(objectElement, i);
                    if (result.Name == controlName)
                    {
                        return result;
                    }
    
                    // Dig recursive into the control
                    int count = VisualTreeHelper.GetChildrenCount(result);
                    if (count > 0)
                    {
                        result = FindName(result, controlName);
                        if (result != null)
                        {
                            return result;
                        }
                    }
                }
    
                // Nothing was found anywhere from any of the controls, their children or content.            
                return null;
            }
        }
     
    Friday, October 31, 2008 3:05 AM
  • I am having this exact issue... has anyone found a better solution yet?  Controls I include in a custom control are not referenceable by name if they are part of a collection.

    Friday, January 23, 2009 4:30 PM
  • Same issue here...  doesn't this qualify as a bug, and is there a better solution/bugfix?

    Thursday, March 26, 2009 6:20 AM
  • When are you calling FindName?  If you call it during an OnLoad handler or the OnApplyTemplate method, it might be too early.  For example, if you use this during the OnLoad handler of one control, that control may have loaded but sibling controls would not necessarily be fully accessible.  Worse would be if what you’re trying to find exists inside of a ContentPresenter defined in a template.

    Things to try would be calling FindName after you’re sure everything has fully initialized.  For debugging purposes this can be as simple as the click handler for a button.  If this succeeds then your problem is timing related. You might have better luck calling FindName on the specific control’s OnLoad and OnApplyTemplate methods.

     

    Thursday, March 26, 2009 5:35 PM
  • Did anybody solve this(FindName not working, when using ContentProperty attribute) problem??
    Thursday, May 21, 2009 8:46 AM
  • I wrote my own search.. FrameworkElement FindNameInTree(FrameworkElement whereToFind, String name) { if (whereToFind == null) return null; if (whereToFind.Name == name) return whereToFind; if (whereToFind as Panel != null) { Panel panelToExplore = whereToFind as Panel; foreach (FrameworkElement child in panelToExplore.Children) { FrameworkElement result = FindNameInTree(child, name); if (result != null) return result; } return null; } else if (whereToFind as UserControl != null) { FrameworkElement content = ((UserControl)whereToFind).GetValue(UserControl.ContentProperty) as FrameworkElement; return FindNameInTree(content, name); } else if (whereToFind as ItemsControl != null) { ItemCollection items = (whereToFind as ItemsControl).Items; foreach (FrameworkElement child in items) { FrameworkElement result = FindNameInTree(child, name); if (result != null) return result; } return null; } else if (whereToFind as ScrollViewer != null) { FrameworkElement fre = (FrameworkElement)((ScrollViewer)whereToFind).Content; return FindNameInTree(fre, name); } return null; }
    Thursday, December 10, 2009 6:17 AM
  • Just for the record because I just found this thread by Goo... Bing: In Silverlight 4, myElement.FindName(string name) seems to find anything now, any child or parent element. Works also if UserControls or ContentControls are involved. The only caveat is that the elements have to have been added to the visual tree already of course, which may be a bit difficult sometimes to find out when for example this functionality is needed in a DependencyProperty's PropertyChangedCallback handler.
    Wednesday, January 27, 2010 7:14 AM
  • Thursday, June 16, 2011 4:52 AM