What is the difference between x:Reference and ElementName? - wpf

According to the x:Reference Markup Extension page on MSDN, x:Reference
References an instance that is declared elsewhere in XAML markup. The reference refers to an element's x:Name.
According to the Binding.ElementName Property page on MSDN, ElementName
The value of the Name property or x:Name Directive of the element of interest.
Looking back at the remarks section on the first page:
x:Reference and WPF
In WPF and XAML 2006, element references are addressed by the framework-level feature of ElementName binding. For most WPF applications and scenarios, ElementName binding should still be used. Exceptions to this general guidance might include cases where there are data context or other scoping considerations that make data binding impractical and where markup compilation is not involved.
For completeness, here is part of the remarks section on the ElementName page:
This property is useful when you want to bind to the property of another element in your application. For example, if you want to use a Slider to control the height of another control in your application, or if you want to bind the Content of your control to the SelectedValue property of your ListBox control.
Now, while I am fully aware of when and how to use the ElementName property, I don't fully understand the difference between it and the x:Reference markup extension. Can anybody please explain this and in particular, expand on the last sentence shown from the x:Reference remarks section?:
Exceptions to this general guidance might include cases where there are data context or other scoping considerations that make data binding impractical and where markup compilation is not involved.

Basically like you said those two do almost the same. However there are small differences under the hood.
{x:Reference ...} -> returns just a reference of an object it doesn't create that "bridge" between two properties like binding would do. Behind all that a service is being used that searches for the given name in a specific scope which is usually the window itself.
{Binding ElementName="..." } -> first of all it creates that binding object then it searches for the object name but not by using the same technique under the hood as x:Reference. The search algorithm moves up and/or down in VisualTree to find the desired element. Therefore a functional VisualTree is always needed. As example when used inside a Non-UiElement, it won't work. In the end the Binding stays and does its daily bread.
This won't work:
<StackPanel>
<Button x:name="bttn1" Visibility="Hidden">Click me</Button>
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Visibility="{Binding ElementName=bttn1, Path=DataContext.Visibility}"/>
....
This works:
<StackPanel>
<Button x:name="bttn1" Visibility="Hidden">Click me</Button>
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Visibility="{Binding Source={x:Reference bttn1}, Path=DataContext.Visibility}"/>
....
Sort of like that :)

ElementName is platform specific. I.e. it may or may not be present based on which platform you're using. x:Reference elevates that concept to a XAML native feature. Thus any platform that supports XAML supports x:Reference.

Related

What are XAML markup extensions?

I tried reading the MSDN article on markup extensions, but I can’t find out what they are (the article discusses what they do).
I cannot find a clear explanation of why we need markup extensions. If we can access a control object directly, why would we need a markup extension to access a binding object?
Do we need markup extensions so XAML is aware of the code behind (otherwise there is no way to get access any of the built in classes)? But then how can we access all the control types?
Markup extensions are not about access but extending functionality of markup (as the name implies) by doing whatever you want them to, like creating associations (Binding, x:Reference) or getting the type of a class (x:Type).
They can be used for just about anything, they are only necessary where the markup does not suffice on its own.
Rationale for markup extensions:
XAML is simple, which is a good thing. It is just an XML-based
language used to declare objects and the relationships between them.
One side effect of being simple is that it can be verbose. This
cumbersome verbosity was one of the main reasons why the concept of
markup extensions was introduced. A markup extension can be used to
turn many lines of XAML into one concise expression...
Another side effect of XAML’s simplicity is that it does not have any
“built in” knowledge of common artifacts used by WPF or the CLR; such
as resource references, data binding, a null value, arrays, static
members of a class, etc. Since XAML can be an integral part of
application development there needs to be some way for developers to
express those ideas in it.
<TextBox >
<TextBox.Text>A text in TextBox</TextBox.Text>
</TextBox>
<TextBox Text="{x:Static system:Environment.UserName}" />
This latter syntax also provides a way to use values other than a literal string (i.e., which is a new object) such as an already constructed object or a static object in our assembly. In this sense markup extensions are objects which decide
how a property's going to be set at runtime.
From https://wpftutorial.net/XAML.html:
Markup extensions are dynamic placeholders for attribute values in
XAML. They resolve the value of a property at runtime.
Markup
extensions are surrouded by curly braces (Example:
Background="{StaticResource NormalBackgroundBrush}").
WPF has some
built-in markup extensions, but you can write your own, by deriving
from MarkupExtension. These are the built-in markup extensions:
Binding
To bind the values of two properties together.
StaticResource
One time lookup of a resource entry
DynamicResource
Auto updating lookup of a resource entry
TemplateBinding
To bind a property of a control template to a dependency property of
the control
x:Static
Resolve the value of a static property.
x:Null
Return null
The first identifier within a pair of curly braces is the name of the extension. All preciding identifiers are named parameters in the
form of Property=Value. The following example shows a label whose
Content is bound to the Text of the textbox. When you type a text into
the text box, the text property changes and the binding markup
extension automatically updates the content of the label.
<TextBox x:Name="textBox"/>
<Label Content="{Binding Text, ElementName=textBox}"/>
Regarding what a markup extension is composed of:
All markup extensions derive from the abstract MarkupExtension class
and override its ProvideValue method. The naming convention is to
append the word Extension to the subclass’s name (only the Binding
class does not follow the pattern).
The XAML parser allows markup
extensions to be created within {curly braces} and it also allows you
to omit the Extension suffix when using a markup extension, if you
want to.
Example code:
<!--- Configure a binding markup extension via the special curly brace syntax --->
<TextBox Text="{Binding Path=Name}" Width="120"/>
<!--- Configure a binding markup extension via the standard element syntax --->
<Checkbox Content="Is person alive?">
<Checkbox.IsChecked>
<Binding Path="IsAlive"/>
</Checkbox.IsChecked>
</Checkbox>
In the XAML above, take a look at the TextBox’s Text property, and the
CheckBox’s IsChecked property. They both use the Binding markup
extension to bind their values to a property on the data context (a
Person object).

How do you navigate a complex Visual Tree in order to re-bind an existing element?

In the above image, child is a ContentPresenter. Its Content is a ViewModel. However, its ContentTemplate is null.
In my XAML, I have a TabControl with the following structure:
<local:SuperTabControlEx DataContext="{Binding WorkSpaceListViewModel}"
x:Name="superTabControl1" CloseButtonVisibility="Visible" TabStyle="OneNote2007" ClipToBounds="False" ContentInnerBorderBrush="Red" FontSize="24" >
<local:SuperTabControlEx.ItemsSource>
<Binding Path="WorkSpaceViewModels" />
</local:SuperTabControlEx.ItemsSource>
<TabControl.Template>
<ControlTemplate
TargetType="TabControl">
<DockPanel>
<TabPanel
DockPanel.Dock="Top"
IsItemsHost="True" />
<Grid
DockPanel.Dock="Bottom"
x:Name="PART_ItemsHolder" />
</DockPanel>
<!-- no content presenter -->
</ControlTemplate>
</TabControl.Template>
<TabControl.Resources>
<DataTemplate DataType="{x:Type vm:WorkSpaceViewModel}">
....
WorkSpaceViewModels is an ObservableCollection of WorkSpaceViewModel. This code uses the code and technique from Keeping the WPF Tab Control from destroying its children.
The correct DataTemplate - shown above in the TabControl.Resource - appears to be rendering my ViewModel for two Tabs.
However, my basic question is, how is my view getting hooked up to my WorkSpaceViewModel, yet, the ContentTemplate on the ContentPresenter is null? My requirement is to access a visual component from the ViewModel because a setting for the view is becoming unbound from its property in the ViewModel upon certain user actions, and I need to rebind it.
The DataTemplate is "implicitly" defined. The ContentPresenter will first use it's ContentTemplate/Selector, if any is defined. If not, then it will search for a DataTemplate resource without an explicit x:Key and whose DataType matches the type of it's Content.
This is discussed here and here.
The View Model shouldn't really know about it's associated View. It sounds like there is something wrong with your Bindings, as in general you should not have to "rebind" them. Either way, an attached behavior would be a good way to accomplish that.
I think the full answer to this question entails DrWPF's full series ItemsControl: A to Z. However, I believe the gist lies in where the visual elements get stored when a DataTemplate is "inflated" to display the data item it has been linked to by the framework.
In the section Introduction to Control Templates of "ItemsControl: 'L' is for Lookless", DrWPF explains that "We’ve already learned that a DataTemplate is used to declare the visual representation of a data item that appears within an application’s logical tree. In ‘P’ is for Panel, we learned that an ItemsPanelTemplate is used to declare the items host used within an ItemsControl."
For my issue, I still have not successfully navigated the visual tree in order to get a reference to my splitter item. This is my best attempt so far:
// w1 is a Window
SuperTabControlEx stc = w1.FindName("superTabControl1") as SuperTabControlEx;
//SuperTabItem sti = (SuperTabItem)(stc.ItemContainerGenerator.ContainerFromItem(stc.Items.CurrentItem));
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(stc);
//ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(sti);
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
The above code is an attempt to implement the techniques shown on the msdn web site. However, when I apply it to my code, everything looks good, except myDataTemplate comes back null. As you can see, I attempted the same technique on SuperTabControlEx and SuperTabItem, derived from TabControl and TabItem, respectively. As described in my original post, and evident in the XAML snippet, the SuperTabControlEx also implements code from Keeping the WPF Tab Control from destroying its children.
At this point, perhaps more than anything else, I think this is an exercise in navigating the Visual Tree. I am going to modify the title of the question to reflect my new conceptions of the issue.

What does (x) in x:Name mean in Silverlight XAML Markup?

We see some properties in TextBlock or Grid like this:
<TextBlock x:Name="TextBlock1" ...
Why do we include this (x)? why don't we just say:
<TextBlock Name="TextBlock1" ...
I mean, we're already within the definition scope of this TextBlock, right?
There must be a reason for that.
Thanks in advance.
As an extension to Gabe's answer, x:Name is an attached property. Attached properties are different from standard properties, as they aren't defined (usually) on the control that uses them. For example, the TextBlock control does not have an x:Name property - instead, this property is defined elsewhere (in the XAML namespace), and is being "attached" to the TextBlock control to implement it's behaviour. It's saying "I want to use the Name attached property that can be found in the XAML namespace). Of course, to complicate things, the TextBlock control has a Name property (it didn't used to in Silverlight 2, thus you needed to use the x:Name attached property instead). They do the same thing though.
Another (easier to understand) example of an attached property is Grid.Row. You can use this property on the TextBlock control to specify what row the control should appear in a Grid, even though it's not defined on that control (the Grid control defines it). The TextBlock is simply attaching that property to itself, which associates itself with that behaviour. It's a confusing concept initially, but very powerful and useful. More info on attached properties can be found here: http://msdn.microsoft.com/en-us/library/cc265152(VS.95).aspx.
Hope this helps...
Chris
That is a namespace prefix.
Example 1:
You should see something like this on the xaml page:
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Which declares the x prefix referring to the xaml namespace.
Example 2:
You could load your own user controls by registering the namespace and giving it a prefix.
xmlns:mycontrols="clr-namespace:MyControls.Namespace;assembly=MyAssembly"
Then here we are using the prefix to utilize one of the controls from this namespace.
<mycontrols:MyControl />

Finding a better way to write complex WPF UIs

The WPF application I've inherited contains a significant amount of XAML which follows a pattern like:
<Window ...>
<Grid>
<z:SomeUserControl>
<z:AnotherUc>
<Label /> <Button /> <ComboBox />
</z:AnotherUc>
<z:AnotherUc>
<Label /> <Button /> <ComboBox />
</z:AnotherUc>
</z:SomeUserControl>
</Grid>
</Window>
In other words, we have UI sections grouped by UserControl, often nested inside other UserControls. At some point, the content is defined using basic WPF content controls.
The problem we're trying to cope with is that the x:Name attribute cannot be applied to any of the inner most controls due to the infamous WPF limitation:
Cannot set Name attribute value {0} on element {1}. {1} is under the scope of element {2}, which already had a name registered when it was defined in another scope
This presents a problem because the code-behind needs to be able to reference elements within the UserControls. UserControls were selected to group parts of the UI because all the styling and templating of default controls because too unwielding and the markup quickly turned in to a horrible, unreadable mess.
However, if Microsoft has no intention of resolving this so-called "limitation," a better way must be found. Considering has been placed in using CS + external XAML template file as seen in GaryGJohnson's work-around on the connect site. However this has a feeling of sphagetti and anything that interrupts bindings is a no-go.
The best option here is typically to avoid using code behind on those "inner" elements. You can still use data binding, so binding these to properties in your DataContext will work properly.
The other alternative, of course, is to expose the Label/Button/ComboBox directly as Dependency Properties of the AnotherUc class. This would allow you to usen them directly as members of the UserControl, which avoids the scoping issue.
The downside to this, of course, is that you must customize the user control for a specific combination of elements, instead of allowing any controls to be placed within it.
Sounds like a mess by design. You can create your own AttachedProperty - MyNameProperty, set it in your XAML and write your own Logical/Visual tree helper, which'll work of it. I'm not saying I would do that, but if you need a quick workaround (w/out radical redesign of you UI composition model), that may do you.

PropertyValueEditor and DependencyObject in Blend 3 - Silverlight DesignTime support

I'm working on a set of controls that has a number of DependencyProperties. The properties are themselves DependencyObjects and created during the get method of the properties. During the Get method, they are also set back to the propertybag using the SetValue() method, so they are in fact valid in Xaml and their properties can be storyboarded without having to explicitly created in the the visual tree.
These DependencyObjects has all its properties as DependencyProperties as well, for supporting DataBinding. They are as mentioned above possible to use in Storyboards.
At the same time I'm developing special designtime support for Blend 3 for these properties and have created an InlineEditorTemplate in the form of a Control. I create the template and set it for the PropertyValueEditor like this:
var vectorEditControl = new FrameworkElementFactory(typeof (VectorEditorControl));
var dataTemplate = new DataTemplate {VisualTree = vectorEditControl};
InlineEditorTemplate = dataTemplate;
In the Control I have the following:
<Grid DataContext="{Binding Value}">
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Path=X, Mode=TwoWay}"/>
<TextBox Text="{Binding Path=Y, Mode=TwoWay}"/>
<TextBox Text="{Binding Path=Z, Mode=TwoWay}"/>
</StackPanel>
</Grid>
The editor shows up and I can edit the data. And even while debugging, I see that it actually sets the data back to the DependencyProperties on the DependencyObjects, but nothing happens to the Xaml. So the data is actually not persisted in any way in the Xaml and lost when I close the Xaml file and open it again.
Is there anything I need to do specifically for it to actually get into the Xaml? I was under the impression that this would happen automatically?
Excellent Question!
The core issue you're running into a misunderstanding as to what PropertyEditors in Blend/Cider end up databinding to.
Consider this object graph:
- MyControl
-- MyControl.MyProperty
--- FooClass
---- FooClass.BarProperty
Let's look at a scenario where we have a PropertyEditor (of any type: Inline, Dialog or Extended) to property MyControl.MyProperty.
When inside MyPropertyPropertyEditor you'd expect to get a fully settable copy of FooClass and be able to manipulate it's members.
That's a good assumption, but the wrong one.
The core issue is that Blend/Cider have elaborate data structures that represent your model at design time. There's about 3-5 levels of abstraction in how Blend/Cider interact with an actual control.
Creating those levels of abstraction allows Expression Blend / Visual Studio designers to be leveraged between framewroks (Silverlight / WPF) and support advanced scenarios (like Property transactions and property chaining).
So, the value you actually get to DataBind to is just one of those levels of abstraction.
Don't believe me? In your custom PropertyEditor, register for this.DataContextChanged event and checkout the type in this.DataContext. You'll end up getting the PropertyValue class (or one of it's friends).
Every single property change you want persisted to XAML (and shown on the design surface) should go through those abstraction layers.
the question you have to ask yourself is "Where do I get one of these absteaction classes for my PropertyValue.Value property instance?".
Well, what I'd do if I were you is create a ModelItem around MyControl.MyProperty and set that as your PropertyEditor.DataContext.
We've shipped an example of using ModelFactory.CreateItem in the Silverlight Toolkit as part of the Chart DefaultInitializer: Source Code, Ning Zhang (Awesome Design Time Dev) explains about ModelItem
If you've got follow-up questions I'd consider pinging PeteBl or UnniR through the Silverlight Insiders mailing list.
Sincerely,
-- Justin
It partly solves my problem. I'm having a dialog with UnniR for a followup.
I couldn't see how I could use this together with the PropertyValueEditor, but for default values this is brilliant and something I'll implement ASAP.
Thanks.

Resources