What is the difference between {x:Static} and {StaticResource} in the XAML code for WPF?
For example:
<StackPanel IsEnabled="{Binding Model.IsReadOnly, Converter={StaticResource BoolInverseConverter}}">
and
<StackPanel IsEnabled="{Binding Model.IsReadOnly, Converter={x:Static BoolInverseConverter}}">
And when should I use one or the other?
Both are markup extensions.
x:Static is used to reference a static attribute, which won't change during runtime. This applies to enumerations, constants, static properties but also fields.
This means your second code example is wrong as you can't reference a class but only a property. Given that BoolInverseConverter is a static property of the Converters class, the correct code would look like:
<StackPanel IsEnabled="{Binding Model.IsReadOnly, Converter={x:Static Converters.BoolInverseConverter}}">
StaticResource does not mean that the resource is static in terms of accessibility but rather in terms of resource lookup. It's a markup extension that instructs the XAML parser to lookup the resource tree to find a predefined instance.
Same does DynamicResource. The only difference is that StaticResource instructs the XAML parser to resolve the reference to a resource at compile time, whereas DynamicResource let's the XAML parser create an expression instead, that will be evaluated at run time (deferred). DynamicResource therefore resolves the resource at run time.
The following code snippet shows how the resource (the converter) is referenced via resource tree lookup by the XAML parser. Since the XAML markup extension StaticResource is used, the lookup is static. This means once the resource was found, it can't be replaced by another instance. And also if the instance is not defined during compile time, the application will crash, throwing a StaticResourceExtension. In case the resource behind the x:key changes during runtime, the references won't update (static):
<StackPanel IsEnabled="{Binding Model.IsReadOnly, Converter={StaticResource BoolInverseConverter}}">
The next code snippet again shows how the resource (the converter) is referenced via resource tree lookup by the XAML parser. But this time using the DynamicResource markup extension, so that the lookup becomes dynamic. This means the resource will be looked up during runtime. And everytime the resource of the specific x:Key changes e.g., a Brush, the referencing instance will update accordingly (dynamic):
<StackPanel IsEnabled="{Binding Model.IsReadOnly, Converter={DynamicResource BoolInverseConverter}}">
Another code snippet shows how to reference an instance, which is not a resource, but a static property defined in the Converters class, using the x:static markup extension:
<StackPanel IsEnabled="{Binding Model.IsReadOnly, Converter={x:Static Converters.BoolInverseConverter}}">
The last code snippet shows another use case of the x:Static markup extension. This time it's used to reference an enumeration value (enum) and sets the Visibility property to a value of the Visibility enumeration:
<StackPanel Visibility="{x:Static Visibility.Collapsed}">
Related
in WPF one can bind to static properties. Now I know 2 ways of doing this:
Content="{x:Static stat:Statics.CurrentUser}"
Or:
Content="{Binding Source={x:Static stat:Statics.CurrentUser}}"
Are there any differences between these 2 methods?
Main difference in this case is that x:Static does not perform additional conversion
From x:Static Markup Extension
Use caution when you make x:Static references that are not directly the type of a property's value. In the XAML processing sequence, provided values from a markup extension do not invoke additional value conversion. This is true even if your x:Static reference creates a text string, and a value conversion for attribute values based on text string typically occurs either for that specific member or for any member values of the return type.
So lets say you do
<TextBlock Text="{x:Static SystemColors.ActiveBorderBrush}"/>
this will cause runtime error:
'#FFB4B4B4' is not a valid value for property 'Text'.
because SolidColorBrush is not String whilst
<TextBlock Text="{Binding Source={x:Static SystemColors.ActiveBorderBrush}}"/>
will work fine and display #FFB4B4B4 because it will perform ToString() conversion. Also without Binding you are not able to access instance properties of static object so for example you would not be able to get Color property of that brush
<TextBlock Text="{Binding Source={x:Static SystemColors.ActiveBorderBrush}, Path=Color}"/>
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.
I'm writing a WPF application in which i want to display the currency symbol of the selected culture on the form.
So i have added this text block
<TextBlock Text="{x:Static globalization:NumberFormatInfo.CurrentInfo.CurrencySymbol}" Style="{StaticResource TextStyle}" VerticalAlignment="Center"/>
The compiler is complaining that it cannot find NumberFormatInfo.CurrentInfo although this is a static property in a public class.
In the same form i'm able to successfully refer to CultureInfo.CurrentCulture from the same namespace. This confirms that i have nothing wrong in my namespace declaration.
My workaround is to provide an x:Name to the textblock and then assign its text from the code behind, but i want to do it the right way.
Thanks,
Fadi
Read the error message carefully, it says where the problem is:
Cannot find the type 'NumberFormatInfo.CurrentInfo'.
It's looking for the property CurrencySymbol of the type NumberFormatInfo.CurrentInfo, which doesn't exist. To bind to that property, you can use the CurrentInfo as a source for Binding:
Text="{Binding Source={x:Static globalization:NumberFormatInfo.CurrentInfo}, Path=CurrencySymbol}"
HI
Am load a string xaml with DynamicResource assigned to a Background property. Is there a way to get the reference of the dynamic resource.
Background="{DynamicResource Color1}"
I want to get the resource reference assigned to a Dependency property at runtime
Pl help
Use FrameworkElement.FindResource Method
this.FindResource("Color1");
Where is the DependencyProperty defined? On the same Window/UserControl? If you simply want to bind to the value of a DependencyProperty you probably want to use regular {Binding ...} syntax instead.
Example 1: If you are binding to a dependency property on a particular control named myControl you can declare it like below.
Background="{Binding ElementName=myControl, Path=Color1}"
Example 2: If you don't want to rely on naming controls because it is so pasay in WPF and you are referencing a property defined on your Window you could do something like below.
Background="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}, Path=Color1}"
Most common way I encountered of specifying a value converter for a binding is to:
1. Create an instance of the value converter as a resource with a key.
2. Reference the instance using StaticResource markup extension:
<TextBlock Text="{Binding Converter={StaticResource myFormatter}" />
Q: Is there anything wrong with using static instance as follows:
<TextBlock Text="{Binding Path=Description, Converter={x:Static local:MyFormatter.Instance}}"/>
// where Instance is declared as:
public readonly static MyFormatter Instance = new MyFormatter();
In my case value converter is immutable.
Edit: another way is to turn the converter into an extension
so that you specify the converter using markup extension format:
<TextBlock Text="{Binding Converter={local:MyFormatter}}"/>
Technically it will be fine, but in practice I don't like it:
If you declare the converter as a resource, then you have a single point of reference. If you change the namespace or class name of the converter, then you only have a single place to update.
If you declare it as static, then you need to bring the clr-namespace in at the top of each and every xaml file that uses the converter. If you declare it as a resource, you don't.
{Binding Converter={StaticResource myFormatter} is much shorter and easier to read than the static one. In the long run, this will help you more than you might think.
As long as the formatter really has no state, this should be fine. It is not equivalent though. In the first case, you have an instance of the class for each instance of your XAML-based control. In the second, only one instance will ever be created.