WPF - Find a child control of a specific type or satisfying a given predicate under a parent control

Ideally you shouldn't be doing this in WPF and MVVM land. However there is an exception to every rule.. mine was I had to set the focus and put a specific cell in a grid into edit mode when the user clicked a button.

Now this is one of the corner cases, for which you need to write some code-behind in the view. Next I needed to get a handle on the datagrid, which was nested within a few expanded data-templates. You can't name this grid, because each expanded data-template would have the same name value.

I did not want to hard code the entire hierarchy path of UI types from the tab to the nested grid. So what I needed was an API like

var grid = tab.FindChild<DataGrid>();

Unfortunately this isn't built-in functionality ; so I look on Stackoverflow and find a relevant question.
However it didn't work for me as is.

Some more debugging and searching later.. I find this post 'Understanding the Visual and Logical tree in WPF' by the always-enlightening WPF Guru Josh Smith. Now I'm not sure I can explain it to a third person..
but here is what I found by tinkering with a test-app.

From My conversations with gullible machines...

  • A DependencyObject can have m logical (shown in bold above) and n visual children.

  • The visual and logical children can overlap. e.g. a StackPanel can be a logical and a visual child of a parent at the same time

  • A logical child can be any object - does not necessarily derive from DependencyObject

With this knowledge, I wrote a few overloads of FindChild - source available here. Pretty self-explanatory.

// find a child textbox with a specific name
var textBox = tab.FindChild<TextBox>( t => t.Name == 'txtName');

// find all child stackpanels meeting a specific criteria (has children)
foreach(var panel in tab.FindChildren<StackPanel>( panel => panel.Children.Count > 0)
{ // do something with panel }

There is also another class - a VM for a Node in the UI Hierarchy, that I used to create the test app. I found it useful for diagnostics. e.g. if you have a reference _contentBox. You can bring up QuickWatch and add the expression 'new UITreeNode(_contentBox)' and visualize the logical and visual hierarchy under it. (Of course you need to paste the class definition into your project temporarily.)

From My conversations with gullible machines...

1 comment:

  1. Hi,
    Very nice and helpful blog.
    Check this link too you might also find this blog helpful.