Accessing the children of an expander control

后端 未结 2 793
有刺的猬
有刺的猬 2021-01-23 22:24

I have a textblock inside the ContentTemplate of an Expander. I want to access that textblock in my code behind file. This is what I have tried so far



        
相关标签:
2条回答
  • 2021-01-23 22:37

    Here is some of my try :

    FAILED TRY

    These two ways which msdn mentioned, after trying I just got null :

    How to: Find DataTemplate-Generated Elements

    How to: Find ControlTemplate-Generated Elements

    .

    And the way link below mention also just got null

    Access a control from within a DataTemplate with its identifying name

    .

    Also simply this.FindName("name") just got null:

    https://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.findname(v=vs.110).aspx

    .

    SUCCESS TRY

    Finally King King's method works,

    In my case I want to find a RichTextBox in the DataTemplate of ContentTemplate, so I write

    yourExpander.IsExpanded = true;
    yourExpander.UpdateLayout();
    //now use your method
    var richTextBox = FindVisualChild<RichTextBox>(yourExpander);
    

    (but I find it works only after the window is initialized and show and when user invoke the event such as mouse click, if I put it into constructor it get null, maybe I'll give it some other try later

    20170328updated: I find use FindVisualChild in the constructor may not find the child, but if you use in the Window_OnLoaded it seems can find, maybe it's because that in the stage of Loaded the controls are become concrete)

    Besides, I test if there're two RichTextBoxes in the DataTemplate of ControlTemplate, this way can only get the first one,

    So, I think a way to modify FindVisualChild to FindRichTextBox so that you can find RichTextBox with specific Name, and before that you have to give name to the control you're finding:

    (you can modify similarly to your finding control type):

        public static RichTextBox FindRichTextBox(DependencyObject obj, string name)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                //                                            add the name condition
                if (child != null && child is RichTextBox && ((RichTextBox)child).Name == name)
                    return (RichTextBox)child;
                else
                {
                    RichTextBox childOfChild = FindRichTextBox(child, name);
                    if (childOfChild != null)
                        return childOfChild;
                }
            }
            return null;
        }
    
    0 讨论(0)
  • 2021-01-23 22:52

    I've tried your code, it's almost fine. I've tried testing it on such as a Button first, it works OK. However for the Expander, it's more complex. There are 2 notices here:

    • Be sure the Expander is expanded (IsExpanded = true).
    • Be sure the layout is updated (you can call UpdateLayout explicitly)

    So the code should be:

    yourExpander.IsExpanded = true;
    yourExpander.UpdateLayout();
    //now use your method
    var textBlock = FindVisualChild<TextBlock>(yourExpander);
    

    Your code can be shorten more like this:

    private childItem FindVisualChild<childItem>(DependencyObject obj) 
                                   where childItem : DependencyObject
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(obj, i);
            if(child is childItem) return (childItem)child;            
            childItem childOfChild = FindVisualChild<childItem>(child);
            if (childOfChild != null) return childOfChild;            
        }
        return null;
    }
    

    Note that child will never be null. Because the GetChildrenCount() already limits the range of existing children, so the child should exist at the specified index i.

    0 讨论(0)
提交回复
热议问题