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
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;
}
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:
IsExpanded = true
).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
.