Binding Source vs x:Static - wpf

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}"/>

Related

Difference between {x:Static} and {StaticResource} in XAML WPF

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}">

NumberFormatInfo.CurrentInfo.CurrencySymbol is not being recognized as a static property in XAML

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}"

WPF databinding and converters

I'm trying to databind to a listbox like so:
<ListBox x:Name="MyListBox" Margin="0,0,0,65">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource MyConverter}}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The reason I am binding to the whole object and not a property is because my converter will need multiple properties of the object to build the string that it returns.
This works and my string is returned. But then when I change the ObservableCollection that this is based on the value doesn't change on the screen. If I bind to just a single property and change it, then the value does change.
What can I do differently? I can't bind to a single property since I need the entire object in the converter... And the ConverterParameter is already being used.
Remember, if you bind to the "main" property and the value of the main property itself isn't changed, the binding will have no reason to refresh itself. It has no clue that your converter is actually based off of a sub-property. What you can do is use a MultiBinding where you bind not only the "main" property, but also a specific sub-property. This gives your IMultiValueConverter implementation access to the main data object, but because you're also binding to the sub-property that's changing, will also be refreshed when that sub-property's value changes.
You can try using a MultiBinding which I believe updates whenever any of its Bindings are triggered. You can also use an IMultiValueConverter or just take advantage of the StringFormat of the binding.

How to access property attributes on a data bound property in Silverlight?

For example, I have a simple textbox bound to a property:
<TextBox Text="{Binding FirstName, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}" />
The property looks something like this:
[Display(Name="Last Name")]
public string LastName { ... }
So, given the textbox, I would like to get the Display Name property from the attribute. This will be used in a composite control that includes a fieldlabel and some other niceties.
Thanks in advance.
I am not able to attempt this at the moment so this may not be accurate or even possible. As soon as I get to a computer that I can try this I will...until then, this is just theory.
I'm guessing in your composite control you'll have something like this for each data bound field:
<TextBlock Text="{Binding FirstName, Mode=OneWay}" />
<TextBox Text="{Binding FirstName, Mode=TwoWay, ...}" />
What you'll probably need to do in order to create a converter that will look at the binding data for the Display attribute, and convert the value to the attribute value instead. This would cause the above block to look like this:
<TextBlock Text="{Binding FirstName, Mode=OneWay, Converter={StaticResource AttributeConverter}, ConverterParameter=Display}" />
<TextBox Text="{Binding FirstName, Mode=TwoWay, ...}" />
Here I passed in the Display as the parameter in case you wanted to access a different attribute.
Again this is just theory since I'm not able to currently test this and cannot recall if IValueConverter.Convert(object value, ...) passes the object in question or just the string value in this case. If it's just the string value, it probably isn't possible, though if it's the object instead, it will depend on how much access you have to the reflection namespace to evaluate the attributes.
As soon as I am able to, I'll throw the scenario together and try it out.
EDIT:
For some reason the sytax highlighter is giving me the finger when I try to paste code in this edit
Anyways, after trying this out in a little project, it don't think you can do this.
Based on my suggestion of making 2 data bound controls and using a converter for the one that consumes the attribute, I did the following:
Created the xaml for the databound control.
Create the Custom Attribute for testing
Created the Model with the decorated property for testing.
Created the converter to attempt to read the attribute from the property.
Here's where I got caught up. I wasn't able to obtain the data bound type from the IValueConverter.Convert(...) method. The value parameter came through as String as did the targetType parameter. While that was the primary hangup, the second was that I was unable to dynamically identify the property name that the control was data bound to. This could be remedied through a converter parameter possibly.
Now, I WAS able to read the attribute value if I supplied the type of my test Model with the decorated property so that much is possible but I wasn't able to dynamically identify the type on the fly.
The only other way I can think of is create some form of observer or converter prior to the data truly being bound to your custom control.
Good Luck

WPF : An alternative way to specify a ValueConverter on binding

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.

Resources