Finding ALL child controls WPF - c#

I would like to find all of the controls within a WPF control. I have had a look at a lot of samples and it seems that they all either require a Name to be passed as parameter or simply do not work.
I have existing code but it isn't working properly:
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
For instance it will not get a DataGrid within a TabItem.
Any suggestions?

You can use these.
public static List<T> GetLogicalChildCollection<T>(this DependencyObject parent) where T : DependencyObject
{
List<T> logicalCollection = new List<T>();
GetLogicalChildCollection(parent, logicalCollection);
return logicalCollection;
}
private static void GetLogicalChildCollection<T>(DependencyObject parent, List<T> logicalCollection) where T : DependencyObject
{
IEnumerable children = LogicalTreeHelper.GetChildren(parent);
foreach (object child in children)
{
if (child is DependencyObject)
{
DependencyObject depChild = child as DependencyObject;
if (child is T)
{
logicalCollection.Add(child as T);
}
GetLogicalChildCollection(depChild, logicalCollection);
}
}
}
You can get child button controls in RootGrid f.e like that:
List<Button> button = RootGrid.GetLogicalChildCollection<Button>();

You can use this Example:
public Void HideAllControl()
{
/// casting the content into panel
Panel mainContainer = (Panel)this.Content;
/// GetAll UIElement
UIElementCollection element = mainContainer.Children;
/// casting the UIElementCollection into List
List < FrameworkElement> lstElement = element.Cast<FrameworkElement().ToList();
/// Geting all Control from list
var lstControl = lstElement.OfType<Control>();
foreach (Control contol in lstControl)
{
///Hide all Controls
contol.Visibility = System.Windows.Visibility.Hidden;
}
}

Related

Adding a control to the main container of unknown object

void Visualize(object CoreObj, object ParentControl)
{
if(CoreObj is typeA)
{
object control1 = new MyControl1(CoreObj);
ParentControl.FirstChild.Children.Add(control1);
foreach (object obj in CoreObj.Children)
{
Visualize(obj, control1);
}
}
else if (CoreObj is typeB)
{
object control2 = new MyControl2(CoreObj);
ParentControl.FirstChild.Children.Add(control2);
foreach (object obj in CoreObj.Children)
{
Visualize(obj, control2);
}
}
}
Where FirstChild is always container, no matter StackPanel, Grid or Canvas, or whatever.
How I get the first child, and the harder part, how to do Children.Add() on object?
I can require something else in case "Children" is inherited from somewhere in all wpf containers, but I can't find out which ancestor/interface contains "Children". Or I can use Reflection probably..
How to do this?
Here's what I came with, finally
interface IContain
{
Panel GetMain(); //return main container
}
// ...
void Visualize(object CoreObj, Panel ParentControl)
{
UIElement control = new UIElement();
if (CoreObj is File) { control = new NameSpacer(); } //new NameSpacer(obj);
else if (CoreObj is Namespace) { control = new NameSpacer(); }
else if(CoreObj is Using) { control = new NameSpacer(); }
if (control.GetType() == typeof(UIElement)) return;
ParentControl.Children.Add(control);
FieldInfo finf = CoreObj.GetType().GetField("Children"); if (finf == null) return;
var val = finf.GetValue(CoreObj); if (val.GetType() != typeof(IEnumerable<object>)) return;
if (control is IContain == false) return;
Panel container = ((IContain)control).GetMain();
foreach (object o in val as IEnumerable<object>)
{
Visualize(o, container);
}
}
You can use VisualTreeHelper class to get the first child.
Children property is defined in abstract class Panel.
var firstChild = parentControl.Descendants().OfType<Panel>().First();
firstChild.Children.Add(control1);
The descendants method leverages VisualTreeHelper in order to get all descendants and you have to define it as extension method:
public static IEnumerable<DependencyObject> Descendants(this DependencyObject element)
{
int childrenCount = VisualTreeHelper.GetChildrenCount(element);
for (int i = 0; i < childrenCount; i++)
{
var visualChild = VisualTreeHelper.GetChild(element, i);
yield return visualChild;
foreach (var visualChildren in Descendants(visualChild))
{
yield return visualChildren;
}
}
}
StackPanel, Grid and Canvas, all derive from the Panel class. This is also the class that contains the Children property.
if you know your argument is a Panel, you also have access to Children.First() and Children.Add(..)

How to programatically expand all expanders in window

I've got a window with some expanders in it.
When you open a expander there is some information inside it.
What i need to do is to open all expanders with one button so everything inside them becomes visible.
When everything is visible i want to print the full page.
This is my code for expanding all expanders now:
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
The lines i use to iterate through my controls:
foreach (Expander exp in FindVisualChildren<Expander>(printpage))
{
exp.IsExpanded = true;
}
Now to the point:
The code above works in most cases.
The only problem i have is that sometimes there are some expanders WITHIN expanders.
The parent expanders do expand when the above code executes, The child expanders however remain unexpanded.
I hope someone can teach me how to expand those child expanders too.
EDIT
I forgot to mention that the child-expanders are not direct childs of the main expanders..
They are children of children of children of the main expanders.
My controll-tree goes something like this:
-Stackpanel
---List item
-----Grid
-------Expander (Main expanders)
---------Grid
-----------Textblock
-------------Expander
So i need to expand all expanders in this tree.
Your code is quite complicated already for what it does. Yields are absolutely not necessary if you call and you really should to execute your method in a recursive fashion.
When, inside your method you encounter a control with children, you call the same method but with a new visual root, which will be a control with children you've just found.
This should work for you (may be a few syntax errors but i'm sure if there are you can fix them)
foreach (Expander exp in FindVisualChildren<Expander>(printpage))
{
exp.IsExpanded = true;
for(int i =0;i<exp.Children.Count;i++)
{
if(exp.Children[i] is Expander)
{
expandChildren(exp.Children[i]);
}
}
}
private expandChildren(Expander exp)
{
exp.IsExpanded = true;
for(int i =0;i<exp.Children.Count;i++)
{
if(exp.Children[i] is Expander)
{
expandChildren(exp.Children[i]);
}
}
}
Okay, I found my anwser in this post
The anwser on this question is what I used to solve my problem.
Here's the function I used:
public static List<T> GetLogicalChildCollection<T>(object parent) where T : DependencyObject
{
List<T> logicalCollection = new List<T>();
GetLogicalChildCollection(parent as DependencyObject, logicalCollection);
return logicalCollection;
}
private static void GetLogicalChildCollection<T>(DependencyObject parent, List<T> logicalCollection) where T : DependencyObject
{
IEnumerable children = LogicalTreeHelper.GetChildren(parent);
foreach (object child in children)
{
if (child is DependencyObject)
{
DependencyObject depChild = child as DependencyObject;
if (child is T)
{
logicalCollection.Add(child as T);
}
GetLogicalChildCollection(depChild, logicalCollection);
}
}
}
In my code I used these lines to append what I needed to my expanders:
List<Expander> exp = GetLogicalChildCollection<Expander>(printpage.StackPanelPrinting);
foreach (Expander exp in expander)
{
exp.IsExpanded = true;
exp.FontWeight = FontWeights.Bold;
exp.Background = Brushes.LightBlue;
}

Visual Tree Helper makes listbox SelectionChanged fire twice

Visual tree code
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
selectionChanged code
private void mylistBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (mylistBox.SelectedItem == null)
return;
foreach (Button tb in FindVisualChildren<Button>(mainListBox))
{
Debug.WriteLine(tb.Name);
}
}
output
Note it writes the name of the two button twice so it loops 4 times and it only has 2 buttons.
optionBtn
optionBtn2
optionBtn
optionBtn2
How many items are there in mainListBox at runtime? It must be 2 and that's why it print the buttons names twice (2 times for each item in the list box). There is nothing wrong with SelectionChanged or VisualTreeHelper

WPF + Controls.UserControl. How to find a control inside?

In my WPF project, I have a System.Windows.Controls.UserControl control. How to find a control inside that contol ?
use VisualTree, if I understood your question correctly.
refer to msdn : http://msdn.microsoft.com/en-us/library/dd409789.aspx
In that case you would probably want to walk the visual tree, like this extension method does:
internal static T FindVisualChild<T>(this DependencyObject parent) where T : DependencyObject
{
if (parent == null)
{
return null;
}
DependencyObject parentObject = parent;
int childCount = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < childCount; i++)
{
DependencyObject childObject = VisualTreeHelper.GetChild(parentObject, i);
if (childObject == null)
{
continue;
}
var child = childObject as T;
return child ?? FindVisualChild<T>(childObject);
}
return null;
}
It requires that you know the type of the control you are looking for.

WPF: Get next /prev visual object

I have a StackPanel containing a number ofTextBox. Is there a way to get the Next / Previous visual elements ?
The functionality I want is fairly analogous to jQuery's .next() function that get the next object.
You can try following method to enumerate the Visual Tree.
public static IEnumerable<T> FindVisualChildren<T>
(DependencyObject depObj, string childName) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
var frameworkElement = child as FrameworkElement;
if (child != null && frameworkElement.Name == childName)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child, childName))
{
yield return childOfChild;
}
}
}
}
Assuming that you named your textBoxes "tbInsideStackPanel", use it like:
foreach (var textBox in FindVisualChildren<TextBox>(this.stackPanel1,
"tbInsideStackPanel").ToList())
{
textBox.Background = Brushes.Blue;
}

Categories

Resources