How could I find a framework element in VisualTree by a predicate?
Something like that :
public static FrameworkElement FindChild(FrameworkElement root, Predicate<> predicate)
{
...
}
I'm goint to use it something like that:
Button btn = FindChild(MainForm, element => element is Button);
Thanks for help in advance!
You may use LINQ to find out the controls of particular type, maybe like this:
List<Button> btns = Controls.OfType<Button>().ToList();
So the real question then is how to iterate throug all the children of the given "root" element.
Because then you'll be able to call your predicate for that element and choose those you want.
So I suppose you should distinguish here two different workflows - one - when the element is Panel, you should first pass it in, and then iterate over it's Children property and pass in every of those (both recursion and non-recursion will work, but you should go deeper into tree, and come back through levels in both cases). And in case of non panel element, just pass in that one to the predicate.
Also you should think about the elements, which have "Content" property (I suppose this is defined in some base type, which I don't remember which one is), so check for the content element the same way. And that's all.
Regards,
Artak
Answers to this SO question describes many ways to look for controls in visual tree.
The predicate version is given there as link to this.
Related
I need to get hold of all the elements in an XDocument, regardless of name, whose value matches some criterion.
The 'matching a criterion' part isn't the problem - the problem is how to get a collection of all the XElements in an XDocument, in other words to flatten it into a 'list' of XElements, without specifying the element names.
myXDocument.Descendants().Where(el => IsAMatch(el.Value))
only seems to return the first level, but the elements in question are nested a variety of levels deep and have a variety of names over which I have no control (and to be honest, no interest either. I just want to find them).
I could do it recursively, walking the tree and adding every matching element to a list, but it doesn't seem very elegant (and is probably quite slow).
How can do I do this more elegantly?
TIA
I can see what is happening now - Descendants() is indeed returning all the elements, but nested elements are returned within their parent elements AND in their own right, which I hadn't spotted. IsAMatch(...) needs to constrain itself to the element's immediate value, ignoring the nested (child) elements.
In my program I have TreeView nodes that I need to be able to shift up and down, basically change the order. My TreeView is an ObservableCollection of a specific Data Model. Each node has a property called "Rank", this is the value that I would like to sort the collection by. With that being said I referred to this question. From that question I discovered this blog page. I am attempting the second method involving the sort function of a List.
This is the example that I am looking at:
List<Person> list = new List<Person>(people);
list.Sort();
Please note that the "Rank" value of each node is in working order and changing correctly. I just need to find a way to re-order the collection based off of that property and reflect it in the View.
My Problem: When trying to implement the above solution I get an InvalidOperationException. I feel like I do not understand how to tell the List to sort based off of rank.
What my code looks like:
List<TreeModel> sortedTree = new List<TreeModel>(TreeCollection);
sortedTree.Sort();
What am I missing here? How do I sort the collection based off of the rank property and reflect those changes in the view?
Thank you.
*I believe I may have posted about this before, so if for some reason this question is too similar my older one, I'll just delete the old one.
Sort throws InvalidOperationException its component type does not have a default comparison:
The default comparer Comparer.Default cannot find an implementation of the IComparable generic interface or the IComparable interface for type T.
You can however supply the comparison as the first parameter to Sort:
sortedTree.Sort((x, y) => x.Rank.CompareTo(y.Rank));
To pass the sorted items back to the original collection, you could either clear/repopulate CurrentCollection, or simply assign it a new instance (don't forget to RaisePropertyChanged if you do the latter):
CurrentCollection = new ObservableCollection<TreeModel>(sortedTree);
You need to pass property name on which you want to sort your list like this -
sortedTree = sortedTree.OrderBy(m => m.Rank).ToList();
I want to show the DOM as it is on the web browser with all comments and html, head, body, etc.. preserve its structure. Currently, I can only start from node html. Document.All didnt help.
The only way I can see is webBrowser1.Document.Body but I would miss the commentss, head etc.. Then if I go with Document.All then that gives me all the nodes.
I think the only choice with the WebBrowser control to get what you want is to use Document.All. Although this gives all elements not just top-level, each element has a .Parent element property so you can loop through them (or use Linq) and get only the ones that have <body> or <head> as the parent element.
Try using HTMLAgilityPack, it support Xpath so you can get any node as you want.
As suggested by hienvd_csuit, I think HTML Agility Pack is your best option. If you still want to use the WebBrowser, a possible solution is to access the unmanaged DOM directly, using dynamic (requires .NET 4+). For instance you can do something like this:
dynamic dom = wb.Document.DomDocument;
foreach (dynamic node in dom.childNodes)
{
Console.WriteLine ("{0} - {1} - {2}", node.nodeType, node.nodeName, node.nodeValue);
}
Of course, you need to know the structure of the DOM, since intellisense doesn't work on dynamic objects; you can find some information about it here.
You should be able to query (there is a property somewhere) if a particular item has a child node or not, also, you can query if it is a parent node or if a particular item has a parent or not, and if it does, discard, and you can keep querying for parent such as item.parent.parent (pls check intellisense for exact object/property names) and if it returns nothing, it means there is only one parent (assuming item.parent doesnt return nothing), and you can organize how many levels deep the nodes can/must be. So based on the child or parent checking method (or both) you can choose to either include it in your collection or discard it.
Of course, you might get many "P" tags or DIV/SPAN tag's as your top level nodes/items. So, i'm assuming there is a chance you will not want these, so feel free to discard them and query their children.
I am parsing an XML document using LINQ to XML and XDocument. Is there a way for a XElement/XContainer to get a child node by the index (in document order)? So that I can get the nth node of the element?
I know I can probably do that by getting all the child nodes of that element and converting that IEnumerable to a List, but that already sounds like it would add a highly redundant overhead (as I am only interested in a single child node).
Is there something I missed in the documentation?
No, there is no indexed access to a child element using XElement or XContainer. If you want indexed access, you have two options.
The first is to call the Elements method on XContainer (which returns an IEnumerable<T> of XElement instances in document order) and then use the Skip extension method to skip over the elements to reach the particular child.
If you want to access the child elements often by index, then you should place them in a IList<T> (which has indexed access), which is easy enough with the ToList extension method:
IList<XElement> indexedElements = element.Elements().ToList();
what about Skip(n).Take(1) operators
Maybe Take(topN) LINQ directive can help?
I'm making assumption based on some SQL related experience - you cannot get the row directly, but can take top n elements.
This can help if your list is huge and you don't encount last elements.
I know i can use LogicalTreeHelper class to find children node for every element searching it by name. But is there a possibility to find a child node by Type? For example, what if i would like to find a ListBox element in my Window without knowing its Name property??
I don't think that there is a built in way of doing this. Probably the best approach would be to recursively call LogicalTreeHelper.GetChildren() until a child control of the specified type is found.
Note that descending the Logical tree cleanly is actually a little tricky, here's a nice article on the intricacies of both the visual and logical trees.
I don't think any helper code exists to do this for you so implementing a recursive walk over the tree is required.