Finding control within WPF itemscontrol - wpf

Hi i have few a single textbox within the the datatemplate for itemscontrol. When i bind the itemcontrols to a observable collection i get two text boxes. But i need to do some manipulations based on each of the text boxes for which i want to find each textbox seperatly using some id.
Can anybody help on how to find a control witin the itemscontrol in WPF.

Using the ItemContainerGenerator you can obtain the generated container for an item and traverse the visual tree downwards to find your TextBox. In the case of an ItemsControl it will be a ContentPresenter, but a ListBox will return a ListBoxItem, ListView a ListViewItem, etc.
ContentPresenter cp = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as ContentPresenter;
TextBox tb = FindVisualChild<TextBox>(cp);
if (tb != null)
{
// do something with tb
}
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;
}
You can also obtain the container by index if you want by using
itemsControl.ItemContainerGenerator.ContainerFromIndex(0);

Thanks Bryce, I tried to tick the up arrow but it says my rating is too low! Sorry!
I amended the code to return all a list of all the children of the given type as it was what I needed and thought someone else might find it useful.
Thanks again Bryce, really helpful - sorry about the rating thing!
public static List<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
List<T> list = new List<T>();
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
list.Add((T)child);
}
List<T> childItems = FindVisualChildren<T>(child);
if (childItems != null && childItems.Count() > 0)
{
foreach (var item in childItems)
{
list.Add(item);
}
}
}
}
return list;
}

You may want to try using VisualTreeHelper. The properties on ItemsControl itself will only allow you to get the data its bound to, not the template instances used to visualize the data, while VisualTreeHelper allows you to browse around the visual tree as WPF has rendered it.
If you iterate through the parent ItemControl's visual children (recursively), you shouldn't have any difficulty locating the text boxes you are seeing on screen.

Another example:
private void DataGridBank_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
{
try
{
switch (e.Key)
{
case Key.Down:
if ((DataGridBank.SelectedIndex + 1) <= DataGridBank.Items.Count)
{
DataGridBank.SelectedIndex = DataGridBank.SelectedIndex + 1;
FocusCell();
}
break;
case Key.Up:
if ((DataGridBank.SelectedIndex - 1) >= 0)
{
DataGridBank.SelectedIndex = DataGridBank.SelectedIndex - 1;
FocusCell();
}
break;
case Key.Enter:
case Key.Tab:
FocusCell();
break;
}
}
catch (Exception ex)
{
}
}
private void DataGridBank_Loaded(object sender, RoutedEventArgs e)
{
try
{
if (DataGridBank.Items.Count > 0)
{
DataGridBank.SelectedIndex = 0;
FocusCell();
}
}catch(Exception ex)
{
}
}
private void FocusCell()
{
var selectedRow = (DataGridRow)DataGridBank.ItemContainerGenerator.ContainerFromItem(DataGridBank.SelectedItem);
var textImport = FindVisualChild<TextBox>(selectedRow);
textImport.Focus();
textImport.SelectAll();
}
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;
}

If you have data grid and template column, which contains data template,
you can use the following code sample
<DataGridTemplateColumn x:Name="photoPathColumn" Header="{x:Static resx:FrmResource.Photo}">
<DataGridTemplateColumn.CellEditingTemplate x:Uid="keyelm">
<DataTemplate x:Name="dodo">
<StackPanel Orientation="Horizontal" Height="Auto">
<TextBlock x:Name="photo" x:Uid="imageFile" Text="{Binding Path=PhotoPath}" />
<Button x:Name="Browse" Content="..." Click="Browse_Click" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
photoPathColumn.CellEditingTemplate.FindName("photo",photoPathColumn.GetCellContent(CustomersDataGrid.CurrentItem))

Related

Parent WPF ListBox doesnt Scroll when the mouse cursor is over a item of its ListBox inside?

I have a ListBox(Parent) and a ListBox inside it(Child). I can't scroll through the items of parent ListBox if the mouse cursor is over a item of child ListBox. How to we can scroll through the parent control irrespective of the item under the mouse cursor. Thanks for help me!
i found a solution for this issues:
private void listBox1_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var scrollViwer = GetScrollViewer(sender as DependencyObject) as ScrollViewer;
if (scrollViwer != null)
{
if (e.Delta < 0)
{
scrollViwer.ScrollToVerticalOffset(scrollViwer.VerticalOffset + 3);
}
else if (e.Delta > 0)
{
scrollViwer.ScrollToVerticalOffset(scrollViwer.VerticalOffset - 3);
}
}
}
public static DependencyObject GetScrollViewer(DependencyObject o)
{
if (o is ScrollViewer)
{ return o; }
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(o); i++)
{
var child = VisualTreeHelper.GetChild(o, i);
var result = GetScrollViewer(child);
if (result == null)
{
continue;
}
else
{
return result;
}
}
return null;
}
Easiest way to solve this:
Set IsEnabled=false on Child Listbox
but I don't now what is your final goal. Btw ScrollViewer (Attached property of ListBox) has tons of property to setup your prefered behavior.

Can I create an extension method for a WPF UserControl that can return a list of its controls?

Is this possible while the controls are not publicly exposed through properties ?
this is easy to achive: (code from this SO question)
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;
}
}
}
}
If a control is part of the Visual Tree of that UserControl, then yes, you can list all the visual children of that control. And you can wrap that logic in an extension method.
You can use VisualTreeHelper class for it.

wpf how to get all TextBoxes in wpf application [duplicate]

I'm looking for a way to find all controls on Window by their type,
for example: find all TextBoxes, find all controls implementing specific interface etc.
This should do the trick:
public static IEnumerable<T> FindVisualChilds<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj == null) yield return (T)Enumerable.Empty<T>();
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject ithChild = VisualTreeHelper.GetChild(depObj, i);
if (ithChild == null) continue;
if (ithChild is T t) yield return t;
foreach (T childOfChild in FindVisualChilds<T>(ithChild)) yield return childOfChild;
}
}
then you enumerate over the controls like so
foreach (TextBlock tb in FindVisualChildren<TextBlock>(window))
{
// do something with tb here
}
This is the easiest way:
IEnumerable<myType> collection = control.Children.OfType<myType>();
where control is the root element of the window.
EDIT - As pointed out in the comments. This only goes one level deep. See the accepted answer for an option that goes deeper.
I adapted #Bryce Kahle's answer to follow #Mathias Lykkegaard Lorenzen's suggestion and use LogicalTreeHelper.
Seems to work okay. ;)
public static IEnumerable<T> FindLogicalChildren<T> ( DependencyObject depObj ) where T : DependencyObject
{
if( depObj != null )
{
foreach( object rawChild in LogicalTreeHelper.GetChildren( depObj ) )
{
if( rawChild is DependencyObject )
{
DependencyObject child = (DependencyObject)rawChild;
if( child is T )
{
yield return (T)child;
}
foreach( T childOfChild in FindLogicalChildren<T>( child ) )
{
yield return childOfChild;
}
}
}
}
}
(It still won't check tab controls or Grids inside GroupBoxes as mentioned by #Benjamin Berry & #David R respectively.)
(Also followed #noonand's suggestion & removed the redundant child != null)
Use the helper classes VisualTreeHelper or LogicalTreeHelper depending on which tree you're interested in. They both provide methods for getting the children of an element (although the syntax differs a little). I often use these classes for finding the first occurrence of a specific type, but you could easily modify it to find all objects of that type:
public static DependencyObject FindInVisualTreeDown(DependencyObject obj, Type type)
{
if (obj != null)
{
if (obj.GetType() == type)
{
return obj;
}
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject childReturn = FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type);
if (childReturn != null)
{
return childReturn;
}
}
}
return null;
}
I found that the line, VisualTreeHelper.GetChildrenCount(depObj);, used in several examples above does not return a non-zero count for GroupBoxes, in particular, where the GroupBox contains a Grid, and the Grid contains children elements. I believe this may be because the GroupBox is not allowed to contain more than one child, and this is stored in its Content property. There is no GroupBox.Children type of property. I am sure I did not do this very efficiently, but I modified the first "FindVisualChildren" example in this chain as follows:
public IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
int depObjCount = VisualTreeHelper.GetChildrenCount(depObj);
for (int i = 0; i <depObjCount; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
if (child is GroupBox)
{
GroupBox gb = child as GroupBox;
Object gpchild = gb.Content;
if (gpchild is T)
{
yield return (T)child;
child = gpchild as T;
}
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
Here is yet another, compact version, with the generics syntax:
public static IEnumerable<T> FindLogicalChildren<T>(DependencyObject obj) where T : DependencyObject
{
if (obj != null) {
if (obj is T)
yield return obj as T;
foreach (DependencyObject child in LogicalTreeHelper.GetChildren(obj).OfType<DependencyObject>())
foreach (T c in FindLogicalChildren<T>(child))
yield return c;
}
}
To get a list of all childs of a specific type you can use:
private static IEnumerable<DependencyObject> FindInVisualTreeDown(DependencyObject obj, Type type)
{
if (obj != null)
{
if (obj.GetType() == type)
{
yield return obj;
}
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
foreach (var child in FindInVisualTreeDown(VisualTreeHelper.GetChild(obj, i), type))
{
if (child != null)
{
yield return child;
}
}
}
}
yield break;
}
Small change to the recursion to so you can for example find the child tab control of a tab control.
public static DependencyObject FindInVisualTreeDown(DependencyObject obj, Type type)
{
if (obj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child.GetType() == type)
{
return child;
}
DependencyObject childReturn = FindInVisualTreeDown(child, type);
if (childReturn != null)
{
return childReturn;
}
}
}
return null;
}
And this is how it works upwards
private T FindParent<T>(DependencyObject item, Type StopAt) where T : class
{
if (item is T)
{
return item as T;
}
else
{
DependencyObject _parent = VisualTreeHelper.GetParent(item);
if (_parent == null)
{
return default(T);
}
else
{
Type _type = _parent.GetType();
if (StopAt != null)
{
if ((_type.IsSubclassOf(StopAt) == true) || (_type == StopAt))
{
return null;
}
}
if ((_type.IsSubclassOf(typeof(T)) == true) || (_type == typeof(T)))
{
return _parent as T;
}
else
{
return FindParent<T>(_parent, StopAt);
}
}
}
}
Do note that using the VisualTreeHelper does only work on controls that derive from Visual or Visual3D. If you also need to inspect other elements (e.g. TextBlock, FlowDocument etc.), using VisualTreeHelper will throw an exception.
Here's an alternative that falls back to the logical tree if necessary:
http://www.hardcodet.net/2009/06/finding-elements-in-wpf-tree-both-ways
My version for C++/CLI
template < class T, class U >
bool Isinst(U u)
{
return dynamic_cast< T >(u) != nullptr;
}
template <typename T>
T FindVisualChildByType(Windows::UI::Xaml::DependencyObject^ element, Platform::String^ name)
{
if (Isinst<T>(element) && dynamic_cast<Windows::UI::Xaml::FrameworkElement^>(element)->Name == name)
{
return dynamic_cast<T>(element);
}
int childcount = Windows::UI::Xaml::Media::VisualTreeHelper::GetChildrenCount(element);
for (int i = 0; i < childcount; ++i)
{
auto childElement = FindVisualChildByType<T>(Windows::UI::Xaml::Media::VisualTreeHelper::GetChild(element, i), name);
if (childElement != nullptr)
{
return childElement;
}
}
return nullptr;
};
#Bryce, really nice answer.
VB.NET version:
Public Shared Iterator Function FindVisualChildren(Of T As DependencyObject)(depObj As DependencyObject) As IEnumerable(Of T)
If depObj IsNot Nothing Then
For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(depObj) - 1
Dim child As DependencyObject = VisualTreeHelper.GetChild(depObj, i)
If child IsNot Nothing AndAlso TypeOf child Is T Then
Yield DirectCast(child, T)
End If
For Each childOfChild As T In FindVisualChildren(Of T)(child)
Yield childOfChild
Next
Next
End If
End Function
Usage (this disables all TextBoxes in a window):
For Each tb As TextBox In FindVisualChildren(Of TextBox)(Me)
tb.IsEnabled = False
Next
For this and more use cases you can add flowing extension method to your library:
public static List<DependencyObject> FindAllChildren(this DependencyObject dpo, Predicate<DependencyObject> predicate)
{
var results = new List<DependencyObject>();
if (predicate == null)
return results;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(dpo); i++)
{
var child = VisualTreeHelper.GetChild(dpo, i);
if (predicate(child))
results.Add(child);
var subChildren = child.FindAllChildren(predicate);
results.AddRange(subChildren);
}
return results;
}
Example for your case:
var children = dpObject.FindAllChildren(child => child is TextBox);
I wanted to add a comment but I have less than 50 pts so I can only "Answer".
Be aware that if you use the "VisualTreeHelper" method to retrieve XAML "TextBlock" objects then it will also grab XAML "Button" objects. If you re-initialize the "TextBlock" object by writing to the Textblock.Text parameter then you will no longer be able to change the Button text using the Button.Content parameter. The Button will permanently show the text written to it from the Textblock.Text write action (from when it was retrieved --
foreach (TextBlock tb in FindVisualChildren<TextBlock>(window))
{
// do something with tb here
tb.Text = ""; //this will overwrite Button.Content and render the
//Button.Content{set} permanently disabled.
}
To work around this, you can try using a XAML "TextBox" and add methods (or Events) to mimic a XAMAL Button. XAML "TextBox" is not gathered by a search for "TextBlock".
For some reason, none of the answers posted here helped me to get all controls of given type contained in a given control in my MainWindow.
I needed to find all menu items in one menu to iterate them. They were not all direct descendants of the menu, so i managed to collect only the first lilne of them using any of the code above.
This extension method is my solution for the problem for anyone who will continue to read all the way down here.
public static void FindVisualChildren<T>(this ICollection<T> children, DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
var brethren = LogicalTreeHelper.GetChildren(depObj);
var brethrenOfType = LogicalTreeHelper.GetChildren(depObj).OfType<T>();
foreach (var childOfType in brethrenOfType)
{
children.Add(childOfType);
}
foreach (var rawChild in brethren)
{
if (rawChild is DependencyObject)
{
var child = rawChild as DependencyObject;
FindVisualChildren<T>(children, child);
}
}
}
}
Hope it helps.
I found it easier without Visual Tree Helpers:
foreach (UIElement element in MainWindow.Children) {
if (element is TextBox) {
if ((element as TextBox).Text != "")
{
//Do something
}
}
};
The accepted answer returns the discovered elements more or less unordered, by following the first child branch as deep as possible, while yielding the discovered elements along the way, before backtracking and repeating the steps for not yet parsed tree branches.
If you need the descendent elements in descending order, where the direct children will be yielded first, then their children and so on, the following algorithm will work:
public static IEnumerable<T> GetVisualDescendants<T>(DependencyObject parent, bool applyTemplates = false)
where T : DependencyObject
{
if (parent == null || !(child is Visual || child is Visual3D))
yield break;
var descendants = new Queue<DependencyObject>();
descendants.Enqueue(parent);
while (descendants.Count > 0)
{
var currentDescendant = descendants.Dequeue();
if (applyTemplates)
(currentDescendant as FrameworkElement)?.ApplyTemplate();
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(currentDescendant); i++)
{
var child = VisualTreeHelper.GetChild(currentDescendant, i);
if (child is Visual || child is Visual3D)
descendants.Enqueue(child);
if (child is T foundObject)
yield return foundObject;
}
}
}
The resulting elements will be ordered from nearest to farthest.
This will be useful e.g. if you are looking for the nearest child element of some type and condition:
var foundElement = GetDescendants<StackPanel>(someElement)
.FirstOrDefault(o => o.SomeProperty == SomeState);

How to access the element within the DataTemplate of GridViewColumnHeader?

How can I get access to an element (TextBlock) within the DataTemplate of GridViewColumnHeader from the code????
I want to set focus on the column header.
Just any GridViewColumnHeader or one in particular? You can use this code
List<GridViewColumnHeader> allGridViewColumnHeaders = GetVisualChildCollection<GridViewColumnHeader>(listView);
foreach (GridViewColumnHeader columnHeader in allGridViewColumnHeaders)
{
TextBlock textBlock = GetVisualChild<TextBlock>(columnHeader);
if (textBlock != null)
{
}
}
And the helper methods
public List<T> GetVisualChildCollection<T>(object parent) where T : Visual
{
List<T> visualCollection = new List<T>();
GetVisualChildCollection(parent as DependencyObject, visualCollection);
return visualCollection;
}
private void GetVisualChildCollection<T>(DependencyObject parent, List<T> visualCollection) where T : Visual
{
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if (child is T)
{
visualCollection.Add(child as T);
}
else if (child != null)
{
GetVisualChildCollection(child, visualCollection);
}
}
}
private T GetVisualChild<T>(DependencyObject parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
{
child = GetVisualChild<T>(v);
}
if (child != null)
{
break;
}
}
return child;
}
Update
To make a GridViewColumnHeader get focus you can
columnHeader.Focus();
Depending on where you do this it might not work, then you can try
EventHandler eventHandler = null;
eventHandler = new EventHandler(delegate
{
listView.LayoutUpdated -= eventHandler;
GridViewColumnHeader columnHeader = GetVisualChild<GridViewColumnHeader>(listView);
columnHeader.Focus();
});
listView.LayoutUpdated += eventHandler;
Also make sure that your GridViewColumnHeader has the following attributes
<GridViewColumnHeader IsTabStop="True" Focusable="True">

How to get DataGridColumnHeader from DataGridColumn?

My code is as follows:
void mainDataContextObj_CutSelectedColumnEvent(string columnId)
{
IList<DataGridColumn> columns = dg.Columns;
for(int i=2; i<dg.Columns.Count; i++)
{
DataGridColumnHeader headerObj = dg.Columns[i].Header as DataGridColumnHeader;
//This always returns headerObj as null!!!
}
}
I need DataGridColumnHeader from the column. Where am I going wrong?
The Header object of the DataGridColumn is actually the visible header of that column, whatever you set it to be. DataGridColumn is not part of the Visual Tree so there is not direct way to access the DataGridColumnHeader for it (we can't even be sure it exists yet). But you can do something like this to try and access it
DataGridColumnHeader headerObj = GetColumnHeaderFromColumn(column);
private DataGridColumnHeader GetColumnHeaderFromColumn(DataGridColumn column)
{
// dataGrid is the name of your DataGrid. In this case Name="dataGrid"
List<DataGridColumnHeader> columnHeaders = GetVisualChildCollection<DataGridColumnHeader>(dataGrid);
foreach (DataGridColumnHeader columnHeader in columnHeaders)
{
if (columnHeader.Column == column)
{
return columnHeader;
}
}
return null;
}
public List<T> GetVisualChildCollection<T>(object parent) where T : Visual
{
List<T> visualCollection = new List<T>();
GetVisualChildCollection(parent as DependencyObject, visualCollection);
return visualCollection;
}
private void GetVisualChildCollection<T>(DependencyObject parent, List<T> visualCollection) where T : Visual
{
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if (child is T)
{
visualCollection.Add(child as T);
}
else if (child != null)
{
GetVisualChildCollection(child, visualCollection);
}
}
}
While Fredrik's answer provides a refactored approach with additional method that could potentially be reused in other parts of the code, I preferred to consolidate his methods in to one single method. There may also be some small performance gain because it can end the search as soon as it finds the header and it does not need to continue to search through all the children in the visual tree (this is most likely negligible for most cases).
private DataGridColumnHeader GetHeader(DataGridColumn column, DependencyObject reference)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(reference); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(reference, i);
DataGridColumnHeader colHeader = child as DataGridColumnHeader;
if ((colHeader != null) && (colHeader.Column == column))
{
return colHeader;
}
colHeader = GetHeader(column, child);
if (colHeader != null)
{
return colHeader;
}
}
return null;
}
And it is used like so:
DataGridColumnHeader colHeader = GetHeader(column, myDataGrid);
if (colHeader == null) { /* Not found */ }

Resources