I am implementing an DragAndDrop-manager for wpf using attached properties. It works quite nice. But there is only one problem. To grab the dragged item i am using the visualtree. As example I want to have the listboxitem but the originalsource is the border of the listboxitem. So I just use one of my helper methods to search for the parent with the type of ListBoxItem. If I found that I get the data of it and drag that.
But I dont want to have my DragAndDrop-manager aviable only while using a listbox. No I want to use it on every Itemscontrol.
But a DataGrid uses DataGridRows, a listview uses ListViewItem... So is there any chance to get the item without writing the code again, again and again?
well, you can have this function
(i prefer to have it as static):
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;
}
}
}
}
and use it some kind of this:
i.e. you want to find all TextBox elements in yourDependencyObjectToSearchIn container
foreach (TextBox txtChild in FindVisualChildren<TextBox>(yourDependencyObjectToSearchIn))
{
// do whatever you want with child of type you were looking for
// for example:
txtChild.IsReadOnly = true;
}
if you want me to provide you some explanation, i'll do this as soon as i get up)
You can use FrameworkElement or UIElement to identify the control.
Control inheritance hierarchy..
System.Object
System.Windows.Threading.DispatcherObject
System.Windows.DependencyObject
System.Windows.Media.Visual
System.Windows.UIElement
System.Windows.**FrameworkElement**
System.Windows.Controls.Control
System.Windows.Controls.ContentControl
System.Windows.Controls.ListBoxItem
System.Windows.Controls.**ListViewItem**
System.Object
System.Windows.Threading.DispatcherObject
System.Windows.DependencyObject
System.Windows.Media.Visual
System.Windows.UIElement
System.Windows.**FrameworkElement**
System.Windows.Controls.Control
System.Windows.Controls.**DataGridRow**
Related
I have TabControl.
I am tring to use:
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject rootObject) where T : DependencyObject
{
if (rootObject != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(rootObject); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(rootObject, i);
if (child != null && child is T)
yield return (T)child;
foreach (T childOfChild in FindVisualChildren<T>(child))
yield return childOfChild;
}
}
}
to find all textboxes from selected TabItem.
I do it because i have list with text for every TextBoxes in TabItem. When i change TabItem i want to save change for last TabItem and reload text for selected TabItem.
I tried use SelectionChanged in TabControl, but it dont work good, and FindVisualChildren dont return any textboxes. It's look like it wasnt initialize. If i run this in Task with dealey nothing changes.
This metod work without problem when is assigned to a separate button. But I would like it to happen automatically.
Xaml show me is there event <EventSetter Event="Initialized" Handler="TabItem_Initialized"/> but it throw The event Initialized is not a RoutedEvent.
How can i detect TabItem will be changed before, and new tab item is initialized?
I'm trying to capture the click event of Hyperlinks inside a dynamically generated RichTextBlock.
I'm dynamically generating the contents of a richtextblock and then applying them with XamlReader. The content can vary quite a bit, so I can't manually parse the xaml and hook up events at that point.
My basic idea is to, once the richtextblock is loaded, find all Hyperlinks in it and hook up their click event there. This is my current code:
public class HookUpEvents()
{
foreach (var child in FindVisualChildren<Hyperlink>(richtxtblock))
{
child.Click += MyFunction;
}
}
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;
}
}
}
}
Obviously, it isn't working. It looks like the FindVisualChildren function isn't returning any Hyperlinks. Any ideas on how I can achieve this?
Well, I'm sure late to the party, but RichTextBlock won't place his Blocks and their Inlines in VisualTree most of the time. To find all Inline-based elements (Run,Span,Bold etc.) you will need to loop through all content, by visiting each Block and subsequent Inline's. I would suggest something like this:
public static IEnumerable<T> GetAllTextElements<T>(this RichTextBlock rtb) where T : TextElement
{
var result = new List<T>();
var blocks = rtb.Blocks;
foreach (var block in blocks)
{
if (block is T)
{
result.Add(block as T);
continue;
}
var inlines = ((Paragraph)block).Inlines;
var res = TraverseInline<T>(inlines);
if (res != null && res.Any())
result.AddRange(res);
}
return result;
}
private static IEnumerable<T> TraverseInline<T>(IEnumerable<Inline> inlines) where T : TextElement
{
var result = new List<T>();
foreach (var item in inlines)
{
if (item is T)
{
result.Add(item as T);
continue;
}
else if (item is Span) // first Inline derived class to have own `Inlines`
{
var spanItem = item as Span;
var spanInlines = spanItem.Inlines;
var results = TraverseInline<T>(spanInlines);
if (results != null && results.Any())
result.AddRange(results);
}
}
return result;
}
So you can look for any TextElement-derived item with it.
Usage would be something like:
var textHyperlinks = myRichTextBlock.GetAllTextElements<Hyperlink>();
This will do as far as you don't use InlineUIContainer. That type of Inline behaves differently, as you can put anything UIElement-based as it's Child property. In that case your initial approach should work.
There's a couple of things here:
If you're trying to find the hyperlink inside of the RichTextBlock, its type is: Windows.UI.Xaml.Documents.Hyperlink. Not the type of the HyperLinkButton.
You can put the Click event handler in your text and then provide the handler method in your code behind file. If you dynamically generate text that looks like:
<Paragraph>
Text with a
<Hyperlink x:Name="link" Click="link_Click">link.</Hyperlink>
</Paragraph>
Feed that to the XamlReader, and put the following code in your code behind file:
private void link_Click(Windows.UI.Xaml.Documents.Hyperlink sender, Windows.UI.Xaml.Documents.HyperlinkClickEventArgs args)
{
Debug.WriteLine("Handle link click, by: " + sender.Name);
}
Then it should connect up correctly at runtime. And you can do whatever you want on the Click event handler. Even if there are multiple links, you can name them differently and just use one click handler to process.
I have a listview(checked list)
- which has checkbox on the header to select all items in the list
Now, I have concern that user should not be able to select the items which are not visible in the list (Hidden due to VerticalScrollBar)
I have 2 solutions for this problem
Select only those items which are visible in the list (which seems difficult)
Disable select all checkbox if there is vertical scroll bar visible
I am going for the 2nd solution in which
I need to know whether verticalScrollBar is appeared or not.
How to know whether VerticalScrollbar of ListView is visible if its visibility is 'Auto'?
You can use ScrollViewer
ScrollViewer sv = FindVisualChild<ScrollViewer>(myListView);
Visibility VerticalScrollbarVisibility = sv .ComputedVerticalScrollBarVisibility;
FindVisualChild implementation example from MSDN
private childItem FindVisualChild<childItem>(DependencyObject obj)
where childItem : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is childItem)
return (childItem)child;
else
{
childItem childOfChild = FindVisualChild<childItem>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
I need to find all TextBox(es) that are on a UWP Page but having no luck. I thought it would be a simple foreach on Page.Controls but this does not exist.
Using DEBUG I am able to see, for example, a Grid. But I have to first cast the Page.Content to Grid before I can see the Children collection. I do not want to do this as it may not be a Grid at the root of the page.
Thank you in advance.
UPDATE: This is not the same as 'Find all controls in WPF Window by type'. That is WPF. This is UWP. They are different.
You're almost there! Cast the Page.Content to UIElementCollection, that way you can get the Children collection and be generic.
You'll have to make your method recurse and look either for Content property if element is a UIElement or Children if element is UIElementCollection.
Here's an example:
void FindTextBoxex(object uiElement, IList<TextBox> foundOnes)
{
if (uiElement is TextBox)
{
foundOnes.Add((TextBox)uiElement);
}
else if (uiElement is Panel)
{
var uiElementAsCollection = (Panel)uiElement;
foreach (var element in uiElementAsCollection.Children)
{
FindTextBoxex(element, foundOnes);
}
}
else if (uiElement is UserControl)
{
var uiElementAsUserControl = (UserControl)uiElement;
FindTextBoxex(uiElementAsUserControl.Content, foundOnes);
}
else if (uiElement is ContentControl)
{
var uiElementAsContentControl = (ContentControl)uiElement;
FindTextBoxex(uiElementAsContentControl.Content, foundOnes);
}
else if (uiElement is Decorator)
{
var uiElementAsBorder = (Decorator)uiElement;
FindTextBoxex(uiElementAsBorder.Child, foundOnes);
}
}
Then you call that method with:
var tb = new List<TextBox>();
FindTextBoxex(this, tb);
// now you got your textboxes in tb!
You can also use the following generic method from the VisualTreeHelper documentation to get all your child controls of a given type:
internal static void FindChildren<T>(List<T> results, DependencyObject startNode)
where T : DependencyObject
{
int count = VisualTreeHelper.GetChildrenCount(startNode);
for (int i = 0; i < count; i++)
{
DependencyObject current = VisualTreeHelper.GetChild(startNode, i);
if ((current.GetType()).Equals(typeof(T)) || (current.GetType().GetTypeInfo().IsSubclassOf(typeof(T))))
{
T asType = (T)current;
results.Add(asType);
}
FindChildren<T>(results, current);
}
}
It basically recursively get the children for the current item and add any item matching the requested type to the provided list.
Then, you just have to do the following somewhere to get your elements:
var allTextBoxes = new List<TextBox>();
FindChildren(allTextBoxes, this);
To my mind, you could do it in the same way as in WPF. Because UWP uses mostly the same XAML that WPF.
So, please check out answer for the same question about WPF
Not sure it is me after a long day of work ... or something is different in WPF type trees. I'm adding data to a tree and then when it is a parent node need to add its children but SelectedItem is always null!
any comment or direction would be helpful.
Thanks.
XAML:
<TreeView x:Name="TreeView1" Grid.Row="0">
</TreeView>
Code:
TreeView myTree = FindChild<TreeView>(Application.Current.MainWindow, "TreeView1");
myTree.Items.Add(ObjEmployee.Tag);
TreeViewItem tvi = (TreeViewItem) myTree.SelectedItem;
//my assumption was that when an item is added to tree most recent used node will be selected but it seems something is avoiding it or maybe works in a different way.
You should post some code snippet .. I do not understand what you need.
If you are using Hierarchical Template ( http://msdn.microsoft.com/en-us/library/ms742521.aspx )
The object of the SelectIedtem will be one of the data you put in ItemsSource
Otherwise, the "SelectedItem" can be any type of visual component that you put inside the treeview.
var treeItem = myTree.SelectedItem;
if (treeItem != null)
treeitem.GetType().Name;
Normally using TreeViewItem inside the treeview, all objects are in treeViewItem.Items
(Edit) You can try this:
var result = FindVisualChildren<TreeViewItem>(treeView);
foreach (var item in result)
{
if (item.IsSelected)
{
....
}
}
and
public static IEnumerable<T> FindVisualChildren<T>(FrameworkElement depObj) where T : FrameworkElement
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
FrameworkElement child = (FrameworkElement)VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}