I would like to find all of the controls within a WPF control specially in Datagrid, DataGridTemplateColumn. 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.
What have you tried that "require a name to be passed or simply don't work" and what's wrong with the former?
private void FindAllChildren()
{
var depObj = dataGrid;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child is DataGridTemplateColumn)
{
// do a thing
}
}
}
Adapted from here: https://stackoverflow.com/a/978352/1189566
Related
Please tell me how to access flipview control inside Hubsection *DataTemplate*
I don't know if you managed to solve your problem already. If you didn't here is how.
private DependencyObject FindChildControl<T>(DependencyObject control, string ctrlName)
{
int childNumber = VisualTreeHelper.GetChildrenCount(control);
for (int i = 0; i < childNumber; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(control, i);
FrameworkElement fe = child as FrameworkElement;
// Not a framework element or is null
if (fe == null) return null;
if (child is T && fe.Name == ctrlName)
{
// Found the control so return
return child;
}
else
{
// Not found it - search children
DependencyObject nextLevel = FindChildControl<T>(child, ctrlName);
if (nextLevel != null)
return nextLevel;
}
}
return null;
}
usage is very simple, for example in my case
ComboBox cb= FindChildControl<ComboBox>(HUB_HC, "SemanaHC") as ComboBox;
Where HUB_HC is my HubSection name and SemanaHC is a combobox inside that HubSection witch is also inside of a StackPanel. It works for me and it's simple to use
Reference: How to access a Control inside the data template in C# Metro UI in the code behind
The best way to deal with this is to have a user control inside the DataTemplate.
And UserControl will have the Flipview, so you can easily access the flipview there.
To access any control inside a HubSection you can do something like this:
var sec = MyHub.Sections[2];
var btn = sec.FindVisualChild("MyButton") as Button;
EDIT: in order to use FindVisualChild extension method you have to use MyToolkit project. You can download it as a Nuget Package and see the project here.
Hope it helps!
:D
EDIT 2: The code for FindVisualChild can be found here: https://mytoolkit.codeplex.com/SourceControl/latest#Shared/UI/FrameworkElementExtensions.cs
var sec = testHub.Sections[0];
var gridViewSelect = sec.FindName("Section4Header") as GridView;
FindName does the trick...
I'm exploring logical and visual trees from the same application without success going deeper through the levels.
My code uses a generic explorer:
private static void ProcessGenericTree(object current, List<FrameworkElement> leaves, Type treeType)
{
if (current is FrameworkElement)
{
if (!leaves.Contains(current as FrameworkElement))
leaves.Add(current as FrameworkElement);
}
DependencyObject dependencyObject = current as DependencyObject;
if (dependencyObject != null)
{
if (treeType.Equals(typeof(VisualTreeHelper)))
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
ProcessVisualTree(VisualTreeHelper.GetChild(dependencyObject, i), leaves);
}
}
else
{
foreach (object child in LogicalTreeHelper.GetChildren(dependencyObject))
{
ProcessLogicalTree(child, leaves);
}
}
}
}
ProcessLogicalTree and ProcessVisualTree simply iterate (doing something before the ProcessGenericTree re-call).
The result looks complete, but when I'm trying to retrieve a TextBlock into a GridViewColumn Header it looks like the item doesn't exist neither in the Logical nor in the Visual leaves list of FrameworkElement.
It seems to be a Visual Element into a Logical Element. In fact adding a watch this TextBlock appears in the Visual Children of my GridView (retrieved as logical, it stands in a Tab Item not selected), but my code isn't unable to get it.
My call is pretty simple:
ProcessVisualTree(root, _visualElements);
ProcessLogicalTree(root, _logicalElements);
where root is the MainWindow.
So, how can I explore my tree at its deepest level? Maybe re-iterating through the retrieved FrameworkElement list? I think my ProcessGeneric code already does it.
Update: the WPF Visualizer shows a structure of this kind:
ListView > ScrollViewer > Grid > DockPanel > Grid > ScrollContentPresenter > GridViewHeaderRowPresenter > GridViewColumnHeader > HeaderBorder
The GridViewColumnHeader level contains my TextBlock but the visual tree doesn't.
Update 2: using the recursion starting from the main window with my element visible I'm not able to Find the object with a specified name with this code:
public static T FindVisualChild<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)
{
return (T)child;
}
T childItem = FindVisualChild<T>(child);
if (childItem != null) return childItem;
}
}
return null;
}
I'm pretty sure the VisualTreeHelper is not able to retrieve elements inside Header property but the WPF Inspector works correctly.
I wonder if it uses a different approach to traverse the tree (maybe inspecting the Properties like Header too). Suggestions?
I have the following code that is supposed to find an element inside of something. The problem is that I have a DataGrid, whose first column has a CheckBox in it's header. The checkbox itself is defined in a Style, which exists in the <controls:ChildWindow.Resources> dictionary of the parent child window.
At runtime, if all elements of the binding collection of the grid are "selected", than I need to select the damn checkbox. However, since the checkbox exists in the style it is not easily accesible and thus I need to walk through the entire DOM to find the specific checkbox.
This is the code that makes the DOM Traversal. It is implemented as an extension method to FrameworkElement so I can call the FindElement or GetChildren methods from any control that inherits from FrameworkElement:
public static class FrameworkElementExtensions
{
public static FrameworkElement FindElement(this FrameworkElement parentFrameworkElement, string childFrameworkElementNameToSearch)
{
FrameworkElement childFrameworkElementFound = null;
parentFrameworkElement.SearchElements(ref childFrameworkElementFound, childFrameworkElementNameToSearch);
return childFrameworkElementFound;
}
public static List<FrameworkElement> GetChildren(this FrameworkElement parentElement)
{
List<FrameworkElement> childFrameworkElementsFound = new List<FrameworkElement>();
parentElement.GetChildren(childFrameworkElementsFound);
return childFrameworkElementsFound;
}
public static void SearchElements(this FrameworkElement parentFrameworkElement, ref FrameworkElement childFrameworkElementToFind, string childFrameworkElementName)
{
int childrenCount = VisualTreeHelper.GetChildrenCount(parentFrameworkElement);
if (childrenCount > 0)
{
FrameworkElement childFrameworkElement = null;
for (int i = 0; i < childrenCount; i++)
{
childFrameworkElement = (FrameworkElement)VisualTreeHelper.GetChild(parentFrameworkElement, i);
if (childFrameworkElement != null && childFrameworkElement.Name.Equals(childFrameworkElementName))
{
childFrameworkElementToFind = childFrameworkElement;
return;
}
childFrameworkElement.SearchElements(ref childFrameworkElementToFind, childFrameworkElementName);
}
}
}
public static void GetChildren(this FrameworkElement parentFrameworkElement, List<FrameworkElement> allChildFrameworkElement)
{
int childrenCount = VisualTreeHelper.GetChildrenCount(parentFrameworkElement);
if (childrenCount > 0)
{
for (int i = 0; i < childrenCount; i++)
{
FrameworkElement childFrameworkElement = (FrameworkElement)VisualTreeHelper.GetChild(parentFrameworkElement, i);
allChildFrameworkElement.Add(childFrameworkElement);
childFrameworkElement.GetChildren(allChildFrameworkElement);
}
}
}
}
So the issue at hand is that when i call something along the lines of SomeDataGrid.FindElement("HeaderCheckBox"); it always returns a null. The assumption here is that I have a DataGrid called SomeDataGrid and a CheckBox defined within a style called HeaderCheckBox.
Upon further debugging I also found out that no matter what control I call these extension methods from, the VisualTreeHelper.GetChildrenCount method call used in the last two methods in my code always returns 0 ??? WTF?
Anyone has any idea on how to fix this?
Thanks,
Martin
Sure, no problem. Here it is.
It was made with VS2010 and Silverlight 4... just in case.
sorry about not making myself clear enough and not putting enough effort (wont happen again :)). i'm building a form App where users have to fill out the form. i have a TabControl with 3 TabItem one of the TabItem has TextBoxes the second has TextBoxes and RadioButton and third has only CheckBoxes. i have written a code to dictect error by on clicking submit using ValidationRule/ValidationResult and and using GroupBinding (got it from msdn samples). now the problem am having is code to search through the tabs, compare the controls (e.g. controlA,controlB) to know wich one comes before the other and return the tabindex. one of the use i want with this is letting the user jump to the uncompleted TextBox,RadioButton or CheckBoxes in order like starting from the first Tabitem in the TabControl
with this code i could work the tree to locate the controls(code from Philipp Sumi blog but i modified it a little)
private void Button_Click(
object sender,
RoutedEventArgs e)
{
IEnumerator enumerator = FindLogicalChildren(_parentStackPanel).GetEnumerator();
while (enumerator.MoveNext())
MessageBox.Show(enumerator.Current.ToString());
}
private IEnumerable FindLogicalChildren(
DependencyObject depObj)
{
if (depObj != null)
{
foreach (object childObj in LogicalTreeHelper.GetChildren(depObj))
{
DependencyObject child = childObj as DependencyObject;
if (child != null && child is Control)
{
yield return (Control)child;
}
foreach (Control childOfChild in FindLogicalChildren(child))
{
yield return childOfChild;
}
}
}
}
but i dodnt know how continue to get the tabindex of each control in order form as i work down the tree. can any one please help me on this? Thanks
im using this method:
private int Compare(
Control controlA,
Control controlB)
{
DependencyObject commonAncestor = controlA.FindCommonVisualAncestor(controlB);
for (int index = 0; index < VisualTreeHelper.GetChildrenCount(commonAncestor); index++)
{
Visual childVisual = (Visual)VisualTreeHelper.GetChild(commonAncestor, index);
Control control = (Control)childVisual;
control.TabIndex = index;
}
return controlA.TabIndex.CompareTo(controlB.TabIndex);
}
that returns 1,-1 or 0 to compare two controls to find out which one comes before the other. the question is, can anyone tell me a better way of doing this.
If i have a component derived from ItemsControl, can I access a collection of it's children so that I can loop through them to perform certain actions? I can't seem to find any easy way at the moment.
A solution similar to Seb's but probably with better performance :
for(int i = 0; i < itemsControl.Items.Count; i++)
{
UIElement uiElement =
(UIElement)itemsControl.ItemContainerGenerator.ContainerFromIndex(i);
}
See if this helps you out:
foreach(var item in itemsControl.Items)
{
UIElement uiElement =
(UIElement)itemsControl.ItemContainerGenerator.ContainerFromItem(item);
}
There is a difference between logical items in a control and an UIElement.
To identify ItemsControl's databound child controls (like a ToggleButton), you can use this:
for (int i = 0; i < yourItemsControl.Items.Count; i++)
{
ContentPresenter c = (ContentPresenter)yourItemsControl.ItemContainerGenerator.ContainerFromItem(yourItemsControl.Items[i]);
ToggleButton tb = c.ContentTemplate.FindName("btnYourButtonName", c) as ToggleButton;
if (tb.IsChecked.Value)
{
//do stuff
}
}