Binding to dictionary using enum as key - wpf

I came across a problem with binding to dictonary property using enum as key in xaml file.
I have a ViewModel with property
public Dictionary<EColor, MyDataStatus> StatusByColor {get; set;}
Where EColor is as enum and MyDataStatus is my own class with property Value.
In a view I'm trying to create a binding
<TextBlock Text="{Binding StatusByColor[enum:EColor.eRed].Value}"/>
and I get an binding error
BindingExpression path error: '[]' property not found on 'object' ''Dictionary`2 .....
However if I enter a digit (instead of using enum) like this:
<TextBlock Text="{Binding StatusByColor[0].Value}"/>
It works perfectly fine
I thought it may be a problem with "including" enum in xaml (it is defined in other assembly) but a few lines below i can use it as CommandParameter like this.
Text="{Binding Path=StatusByColor, Mode=OneWay,
Converter={StaticResource statusByColorToDayElapsedConverter},
ConverterParameter={x:Static enum:EPaintColor.eRed}}"
And in this scenario (with converterParameter) even IntelliSense suggests enum's values.
This is how I "include" enum in xaml:
"xmlns:enum="clr-namespace:CommonTypes.Enums;assembly=CommonTypes""

Firstly,Give my answer,and I have verified it.
<TextBlock Text="{Binding StatusByColor[eRed].Value}"/>
I tried your code with a sample and get the same result as you mentioned.
But when I try this code.
<TextBlock Text="{Binding StatusByColor[0].Value}"/>
I changed the index from 0 to 999.I got an exception
"System.Collections.Generic.KeyNotFoundException"
So I confirm that there is a type casting from Int to Enum.
However,only Int can be converted? How about string?
Yes!String also worked.
Refer:
WPF Binding to items within a dictionary by key?

Related

Bind a textblock to static property which isn't in the VM

This is my xaml code:
<TextBlock Text="{Binding MyTranslations[0].Name}"></TextBlock>
What I want to do is remove the 0. Instead of 0, I need to get the correct integer from a static field in a static class which is in another project but in the samo solution.
I guess it should look like something like this:
<TextBlock Text="{Binding MyTranslations[MyStaticClass.MyStaticInt].Name}"></TextBlock>
How do I do this?
There is probably some strange way to do this syntactically in xaml, but usually when I come across strange problems like this, I usually just make a calculated property in my VM.
public string MyCurrentTranslation
{
get { return MyTranslations[MyStaticClass.MyStaticInt].Name; }
}
Then just bind to that property:
<TextBlock Text="{Binding MyCurrentTranslation}"/>

Binding Source vs x:Static

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

How to bind to a dictionary entry with key ending in '{'?

I want to bind to a value in a dictionary property of an object. The dictionary key of this value is a string ending in '{'. How do I express this in XAML?
I presumably need to escape this character somehow.
Example XAML that doesn't work:
<TextBlock Text="{Binding Attribs[test{]}" />
Here Attribs is a property on the datacontext object of type IDictionary<string, object>
This XAML works, by avoiding using a binding expression and instead using a Binding element:
<TextBlock>
<TextBlock.Text><Binding Path="Attribs[test{]"/></TextBlock.Text>
</TextBlock>
I just have tested the following XAML fragment, and it seems to work fine:
<TextBlock Text="{Binding Attribs[test\{]}"/>
The \ escape character is explained in this article.

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

Databinding issue with textbox and accessors

I am wondering what am I missing? The binding is not displaying at all in the textbox. These are my codes:
XAML Namespace:
xmlns:c="clr-namespace:mySystem.Workspace"
DataContext and Resources:
<Grid.Resources>
<c:Parameter x:Key="mySource"/>
</Grid.Resources>
<Canvas>
<Canvas.DataContext>
<Binding Source="{StaticResource mySource}" />
</Canvas.DataContext>
Textbox:
<TextBox x:Name="TextBox" Width="159" Height="26" Canvas.Left="36" Canvas.Top="47">
<TextBox.Text>
<Binding Path="JobKey" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
The class:
namespace mySystem.Workspace
{
public class Parameter : Object
{
The accessors:
public BasePar JobKey
{
get { return jobKey; }
set { jobKey = value; }
}
There are lots of odd things here but the most obvious one that will get you working is that the Binding Path is case sensitive.
Change your binding to:
<Binding Path="JobKey" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
This should get the binding working.
I'm also not sure what type BasePar is, or is meant to be, but unless you are doing something clever intentionally, just make it a standard type like string.
You should also probably not use the namespace System.Workspace, but something related to your own project.
After your response, the only thing I can guess that the BasePar object is intended for, is to be used within a DataTemplate, on an ItemsControl say. DataTemplates have the behaviour that when they do not know how to render an Object they will fall back the the Object's .ToString() method.
Now, in my comment I said that I don't think the TextBox can have a DataTemplate, and I believe this is true however I did find a trick at this Stackoverflow question which templates a content control and a textblock instead. The code is below:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:System.Workspace"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<c:Parameter x:Key="mySource"/>
<DataTemplate x:Key="MyDataTemplate">
<TextBlock Text="{Binding}"/>
</DataTemplate>
</Grid.Resources>
<Canvas>
<Canvas.DataContext>
<Binding Source="{StaticResource mySource}" />
</Canvas.DataContext>
<ContentControl
Content="{Binding Path=JobKey}"
ContentTemplate="{StaticResource MyDataTemplate}" />
</Canvas>
</Grid>
I don't have time right now to get the TextBox working - don't even know if it is possible, given my first few tries. However, this might help get you where you need to go.
But still - if I was me I'd just use simple binding to standard objects. I can't see the benefit of the BasePar class in this scenario.
What does the BasePar implementation look like? Have a look in the Debug Output window to see if you have a line like this:
System.Windows.Data Error: 1 : Cannot create default converter to perform 'two-way' conversions between types 'WpfApplication1.BasePar' and 'System.String'. Consider using Converter property of Binding. BindingExpression:Path=JobKey; DataItem='Parameter' (HashCode=14209755); target element is 'TextBox' (Name='TextBox'); target property is 'Text' (type 'String')
This is telling you that you are trying to bind to the property, but WPF cannot create a 2-way binding, because it cannot convert the text (you type into the TextBox) into a 'BasePar' object.
As per David's suggestion, you could bind to a primitive string type, or alternately (as per the warning message above) you could add a Converter to the binding to convert a string into a BasePar.
you need to make jobkey a DependencyProperty by deriving it from DependencyObject or derive your class from INotifyPropertyChanged and add all the notify code, etc.
if you do not do this, then you will not receive update notifications and your bindings wont work as expected.
Path="jobKey"
You need to bind to the property not the field, i.e. make that upper-case. Also: To debug bindings check the Output-window in Visiual Studio.

Resources