patterncsharpModerate
Is there a better way to get a child?
Viewed 0 times
waybettergetchildthere
Problem
I have written the following code to get
Here's the control template XAML of the
Is there a better way to get the
ImageColorPicker child:foreach (CustomTabItem customTabItem in SelectedWindowsTabControl.Items)
{
TabItem ti = tabControl.ItemContainerGenerator.ContainerFromItem(customTabItem) as TabItem;
Popup popup = (Helpers.FindVisualChild(ti) as Popup);
ImageColorPicker icp = (popup.Child as StackPanel).Children[0] as ImageColorPicker;
...
}
public class Helpers
{
///
/// Return the first visual child of element by type.
///
/// The type of the Child
/// The parent Element
public static T FindVisualChild(DependencyObject obj) where T : DependencyObject
{
for (int i = 0; i (child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
}Here's the control template XAML of the
TabItem (the relevant part):
Is there a better way to get the
ImageColorPicker than what I've done? (getting the TabItem, then the Popup and then the ImageColorPicker, I am sure there's a shorter way)Solution
I don't like a class that's just called
I'm using a very similar method - the main difference is essentially the number ot
Notice the guard clause preventing a
That said, it might be personal preference, but I think the readability of your code could benefit from implicit typing (
Becomes:
And here you would have to make sure
Also, you're casting too much -
Update
The
You're not fully using the recursiveness of your function when you're getting the color picker. I'd believe you could get it like this:
That should work, because the search is recursive; you don't need to get everything in-between.
Helpers - that's generally a code smell, something that ends up a big dumping ground for anything that doesn't quite fit anywhere else. Be more specific when naming things, perhaps VisualHierarchyHelper would be a better name?I'm using a very similar method - the main difference is essentially the number ot
return statements, and the childName parameter; I found this code on Stack Overflow a little while ago:///
/// Finds a Child of a given item in the visual tree.
///
/// A direct parent of the queried item.
/// The type of the queried item.
/// x:Name or Name of child.
/// The first parent item that matches the submitted type parameter.
/// If not matching item can be found,
/// a null parent is being returned.
///
/// https://stackoverflow.com/a/1759923/1188513
///
public static T FindChild(this DependencyObject parent, string childName)
where T : DependencyObject
{
if (parent == null) return null;
T foundChild = null;
var childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (var i = 0; i (child, childName);
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
if (frameworkElement != null && frameworkElement.Name == childName)
{
foundChild = (T)child;
break;
}
}
else
{
foundChild = (T)child;
break;
}
}
return foundChild;
}Notice the guard clause preventing a
NullReferenceException that your method would throw if obj was null. I think this is a pretty neat way of finding a child node in the visual tree.That said, it might be personal preference, but I think the readability of your code could benefit from implicit typing (
var), especially in cases like this where the type is already pretty obvious:TabItem ti = tabControl.ItemContainerGenerator.ContainerFromItem(customTabItem) as TabItem;
Popup popup = (Helpers.FindVisualChild(ti) as Popup);
ImageColorPicker icp = (popup.Child as StackPanel).Children[0] as ImageColorPicker;Becomes:
var ti = tabControl.ItemContainerGenerator.ContainerFromItem(customTabItem) as TabItem;
var popup = (Helpers.FindVisualChild(ti) as Popup);
var icp = (popup.Child as StackPanel).Children[0] as ImageColorPicker;And here you would have to make sure
popup isn't null before accessing its Child member, if you want to avoid that possible NullReferenceException.Also, you're casting too much -
T should be of the type you've specified, so the return type of FindChild is ImageColorPicker, casting it to ImageColorPicker is redundant.Update
The
ImageColorPicker child has a Popup parent, which has a StackPanel parent, which has a Grid parent, which has a TabItem parent.You're not fully using the recursiveness of your function when you're getting the color picker. I'd believe you could get it like this:
var tab = tabControl.ItemContainerGenerator.ContainerFromItem(customTabItem) as TabItem;
var picker = VisualHierarchyHelper.FindChild(tab, "ColorPicker");That should work, because the search is recursive; you don't need to get everything in-between.
Code Snippets
/// <summary>
/// Finds a Child of a given item in the visual tree.
/// </summary>
/// <param name="parent">A direct parent of the queried item.</param>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="childName">x:Name or Name of child. </param>
/// <returns>The first parent item that matches the submitted type parameter.
/// If not matching item can be found,
/// a null parent is being returned.</returns>
/// <remarks>
/// https://stackoverflow.com/a/1759923/1188513
/// </remarks>
public static T FindChild<T>(this DependencyObject parent, string childName)
where T : DependencyObject
{
if (parent == null) return null;
T foundChild = null;
var childrenCount = VisualTreeHelper.GetChildrenCount(parent);
for (var i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
var childType = child as T;
if (childType == null)
{
foundChild = FindChild<T>(child, childName);
if (foundChild != null) break;
}
else if (!string.IsNullOrEmpty(childName))
{
var frameworkElement = child as FrameworkElement;
if (frameworkElement != null && frameworkElement.Name == childName)
{
foundChild = (T)child;
break;
}
}
else
{
foundChild = (T)child;
break;
}
}
return foundChild;
}TabItem ti = tabControl.ItemContainerGenerator.ContainerFromItem(customTabItem) as TabItem;
Popup popup = (Helpers.FindVisualChild<Popup>(ti) as Popup);
ImageColorPicker icp = (popup.Child as StackPanel).Children[0] as ImageColorPicker;var ti = tabControl.ItemContainerGenerator.ContainerFromItem(customTabItem) as TabItem;
var popup = (Helpers.FindVisualChild<Popup>(ti) as Popup);
var icp = (popup.Child as StackPanel).Children[0] as ImageColorPicker;var tab = tabControl.ItemContainerGenerator.ContainerFromItem(customTabItem) as TabItem;
var picker = VisualHierarchyHelper.FindChild<ImageColorPicker>(tab, "ColorPicker");Context
StackExchange Code Review Q#44760, answer score: 14
Revisions (0)
No revisions yet.