Ok, I know that FrameworkElement, which is a direct subclass of UIElement, has a Parent property, but Panels have children of type UIElement, not FrameworkElement (Children is of type UIElementCollection) which seems it would mean you can add UIElements directly to a Panel.
That said, if you have a UIElement and want to see if it has a parent that's a panel, the only way I know how to test this is with the VisualTreeHelper, but that's the visual tree, not the logical tree. (At least we know a Panel doesn't have a template so maybe that's the way, but still...)
So asides from the VisualTreeHelper, does anyone know how to know which panel is the parent of a UIElement? (...and have any thoughts why they didn't just define a Parent property there instead of on FrameworkElement?)
Thanks!
Well, if you need to find a logical parent you can just use LogicalTreeHelper in the same manner as VisualTreeHelper.
As for "...and have any thoughts why they didn't just define a Parent property there instead of on FrameworkElement?". Basically, the notion of "Logical Tree" is introduced on the FrameworkElement level. See http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.aspx (see Remarks) for details of what FrameworkElement adds to UIElement. Here is what it says about Logical Trees:
The logical tree: The general WPF
programming model is often expressed
in terms of being a tree of elements.
Support for expressing the tree of
elements as a logical tree, and
accompanying support for defining that
tree in markup is implemented at the
FrameworkElement level. Note however
that FrameworkElement deliberately
does not define a content model, and
leaves that responsibility to derived
classes. For more information, see
Trees in WPF.
Related
In a WPF application using a fairly standard MVVM pattern, I need to bind from a row in a DataTable (i.e. deep inside the visual tree) to the data context of the whole window. I am assuming the only way to do this is to use Mode=RelativeSource, but it requires that I specify the AncestorLevel.
How do I determine the AncestorLevel?
Why should I need to specify this at all when I know there is only ever one window? In other words, why can't I simply specify the type I want to bind to and have the binding engine reverse up the tree until it finds the first object of the required type?
If I do figure out the AncestorLevel, doesn't this make the code brittle? (If I change the nesting of the visual elements, it will obviously break.)
If there is no good solution involving RelativeSource, I thought I could take an alternative approach and 'propagate' the page-level property down through the logical tree to the individual items in the list. Is there an accepted pattern for this?
Has RelativeSource ever had a way of traversing up the tree searching only by type (or am I imagining this)?
See my question, similar issue was raised there:
WPF finding ancestor for binding
In short - when you give the ancestor type, it is searched upwards the elements tree until the ancestor of that given type is found (Level 1). Should you need to search two levels up (e.g. you have a grid in a grid and you're aiming for the "outer" grid), you specify AncestorLevel=2 and the ancestor is then a second element of that particular type while traversing the elements tree.
How do I determine the AncestorLevel?
By looking at the visual tree and figuring out the number of occurances of a specific type of parent element. There can only be only one top-level parent window though.
Why should I need to specify this at all when I know there is only ever one window?
You don't have to. It's perfectly fine and also very common to only specify the AncestorType like this:
{Binding SomePropertyOfTheWindow, RelativeSource={RelativeSource AncestorType=Window}}" />
If I do figure out the AncestorLevel, doesn't this make the code brittle? (If I change the nesting of the visual elements, it will obviously break.)
Yes, this is correct, but this is how you tell the binding engine to which particular item of a specific type that you want to bind to - assuming there are several to choose from.
Although this is not binding to a Relative source, but another way of binding without the complexities of Relative and type.
Another option instead of binding to a specific type of control, you can name your controls in the xaml with x:Name. Then you can bind directly to that control and property on it. Ex:
<SomeControl x:Name="IWantThisControl" />
[bunch of other controls]
<YourOtherControl ThisControlProperty={Binding ElementName=IWantThisControl, Path=PropertyOnTheOtherControl}" />
It does not matter the nesting level of the controls when you use the binding to ElementName reference.
Given a FrameworkElement, how do I traverse the DataConext "up" in C# code behind (not binding)? For example: A customer has multiple addresses, if I click on a button on the Address layout I would like to find the Customer. I have read the MSDN article on the VisualTree and the LogicalTree but I'm struggling to put it all together.
Please send codez :)
Well ideally your DataContext instances are all part of a hierarchy that have a parent and child relationship. That way you can always move up the parent chain. This is the advantage of a ViewModel approach where the base class implementation maintains a parent reference and automatically sets it up when adding children. When this is not the case...
Use the following static method to move up the chain...
VisualTreeHelper.GetParent
...note that the method expects a DependencyObject which is a base class of the FrameworkElement.
I don't know if this should go on Programmers, but I thought it was relevant here.
Being a skilled WPF programmer myself, I often wonder what people were thinking when they designed WPF in terms of naming conventions.
Why would you sometimes have a property called Children for accessing the children of the control, and then sometimes have an equivalent property, just called Controls instead? What were they thinking here?
Another example is the Popup control. Instead of a Content property, it has a Child property. Why would you do that? To me that's just confusing.
So I'm wondering if there's a logical reason for it, which would probably also help me understand what the properties are called next time I need to do some speed-programming.
If there's no reason behind it, then all I can say is WAT.
I've never seen a Controls property; as for Child versus Content: Content can be any object, data for example, whereas a Child has to be some FrameworkElement in the hierarchy of the controls. To me that makes perfect sense.
When do I derive from UIElement and FrameworkElement considering FrameworkElement inherits UIElement. Can anyone give real life examples?
This is a good page for learning about WPF Architecture, and this answer only applies to WPF. Check out the UIElement and FrameworkElement sections, as well as the rest if you have time. Here's a quote from the linked page explaining why the 2 levels exist:
To this point in the topic, "core" features of WPF – features implemented in the PresentationCore assembly, have been the focus. When building WPF, a clean separation between foundational pieces (like the contract for layout with Measure and Arrange) and framework pieces (like the implementation of a specific layout like Grid) was the desired outcome. The goal was to provide an extensibility point low in the stack that would allow external developers to create their own frameworks if needed.
In short, UIElements know how to draw themselves (because they are derived from Visual). They can also use the routed events system by providing virtual methods like OnPreviewMouseDown and OnMouseDown, and part of the layout system by implementing Measure and Arrange.
FrameworkElements extend the layout system by implementing some of the virtual methods defined in UIElement. They provide a consistent way of setting layout properties, e.g. the Margin property and the MinWidth property. Additionally, the can be styled, and they can take part in data binding.
In answer to your question, if you need any of the extra abilities that FrameworkElement add, e.g. you need styles, binding or a layout system that's easier to use, then derive from them. Otherwise, derive from UIElement as there is a slight overhead from using FrameworkElement.
Also, you should have a look at the Control class (derived from FrameworkElement), as these provide useful new layers of functionality like Templating and properties like Padding.
Familiarising yourself with the inheritance hierarchy is also a good idea, you might want to derive from other classes in it (though probably no higher up the chain than Visual).
I don't have any examples right now, but I can refer you to links that might help.
UIElement is a base class for most of the objects that have visual appearance and can process basic input in Silverlight.
FrameworkElement provides a framework of common APIs for objects that participate in Silverlight layout. FrameworkElement also defines APIs related to data binding, object tree, and object lifetime feature areas in Silverlight.
So what additional capabilities do you get? See http://forums.silverlight.net/p/205863/482651.aspx
On my MainPage.xaml, I sometimes need to add a UserControl to the main Panel (a Canvas). That UserControl, when clicked, needs to access a routine from MainPage.xaml - it's parent's parent - which will either make the UserControl itself Visibility = Collapsed or removed all together from MainPage.xaml.
Right now in the code behind of that UserControl I am doing
Dim c = VisualTreeHelper.GetParent(Me)
Dim mp As MainPage = VisualTreeHelper.GetParent(c)
mp.MyRoutine(3)
This is working, but it makes me wonder if there is a more straight-forward way to do this or a more preferred way. Any ideas?
A more general way of navigating the visual tree is available via Linq To VisualTree, with this small framework you can perform all sorts of queries on your visual tree. Your example of getting parent would be as simple as:
var parent = me.Ancestors().First();
Or, if you want to find the first parent of a given type ...
var parent = me.Ancestors<MainPage>().Cast<MainPage>().First()
In general, I'd avoid this type of dependency. It dramatically reduces the usefulness and flexibility of your UserControl.
Instead, it might be better to push the dependency into the UserControl during construction (or even runtime). You could pass in a delegate referencing MyRoutine, or an interface the main page implements.
This way, the UserControl's dependency would be obvious (since it's part of the API), and it would be possible to use it with other applications/pages later.
That being said, if you decide to keep the above, I would make one change at a minimum. Instead of just expecting the parent's parent to always be "MainWindow", I would recursively check parents until you get to the MainWindow (or nothing) in a method on your class. This would, at a minimum, allow you the flexibility of moving your UserControl around in the hierarchy without breaking it.
The general way that I navigate the visual tree is with my own VisualTreeEnumeration code. However as I state in the blog there are other various utilities to do the same. Whatever you use you end up with an enumerable set of ancestors. However the most most flexiable approach would be to hunt for the MainPage type:-
(Note C#)
MainPage mp = this.Ancestors().OfType<MainPage>().FirstOrDefault();
Not sure what this would look like VB.