WPF: Get next /prev visual object - c#

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;
}

Related

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;
}

FindVisualChild reference issue

I have found and modified following code in order to export my dataGrid to a pdf document using iTextSharp class.
private void ExportToPdf(DataGrid grid)
{
PdfPTable table = new PdfPTable(grid.Columns.Count);
using (Document doc = new Document(iTextSharp.text.PageSize.A4))
{
using (PdfWriter writer = PdfWriter.GetInstance(doc, new System.IO.FileStream("Test.pdf", FileMode.Create)))
{
doc.Open();
for (int j = 0; j < grid.Columns.Count; j++)
{
table.AddCell(new Phrase(grid.Columns[j].Header.ToString()));
}
table.HeaderRows = 1;
IEnumerable itemsSource = grid.ItemsSource as IEnumerable;
if (itemsSource != null)
{
foreach (var item in itemsSource)
{
DataGridRow row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
if (row != null)
{
DataGridCellsPresenter presenter = FindVisualChild<DataGridCellsPresenter>(row);
for (int i = 0; i < grid.Columns.Count; ++i)
{
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(i);
TextBlock txt = cell.Content as TextBlock;
if (txt != null)
{
table.AddCell(new Phrase(txt.Text));
}
}
}
}
doc.Add(table);
doc.Close();
}
}
}
}
The problem occurs in the following line:
DataGridCellsPresenter presenter = FindVisualChild<DataGridCellsPresenter>(row);
Visual Studio returns following error 'The name 'FindVisualChild' does not exist in the current context'. How do I add this parameter ?.
FindVisualChild method is not provided by WPF framework, you have to add them. May be you want this:
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;
}
}
}
}
public static childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject
{
foreach (childItem child in FindVisualChildren<childItem>(obj))
{
return child;
}
return null;
}
Add these methods in some utility class so they can be reuse.
Also a common practice is to use these methods (posted by Rohit Vats) as extension methods, like this:
static class Utils
{
public static IEnumerable<T> FindVisualChildren<T>(this DependencyObject depObj)
where T : DependencyObject
{
...
}
public static childItem FindVisualChild<childItem>(this DependencyObject obj)
where childItem : DependencyObject
{
...
}
}
And then in your code:
using Utils;
class MyCode
{
public static DataGridCellsPresenter GetPresenter(DataGridRow row)
{
return row.FindVisualChild<DataGridCellsPresenter>();
}
}

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

Finding ALL child controls WPF

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;
}
}

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.

Categories

Resources