How to pass Static Resource String to ConverterParameter in UWP - c#

I m doing an UWP project and I wan't to format a string using a converter and Static resource String because the application is in mulitple languages.
Here is my converter :
public class StringFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
return null;
if (parameter == null)
return value;
return string.Format((string)parameter, value);
}
public object ConvertBack(object value, Type targetType, object parameter,
string language)
{
throw new NotImplementedException();
}
}
Here the string in my Resource Strings.Xaml file :
<x:String x:Key="nbItems">You have {0} items...</x:String>
Here the element where I wan't to pass this formatter :
<TextBlock Text="{x:Bind NbItems, Converter={StaticResource StringFormatConverter}, ConverterParameter={StaticResource nbItems}, Mode=OneWay}"/>
It's not working but if I do like this it works :
<TextBlock Text="{x:Bind NbItems, Converter={StaticResource StringFormatConverter}, ConverterParameter='You have {0} items..', Mode=OneWay}"/>
The parameters is always null in my converter, why it's not working ?

Not exactly certain why the parameter is null, however I have come up with a workaround. Move your strings into a Resource file (see here).
Then change the parameter you pass to your converter to the String Name, like so:
<TextBlock Text="{x:Bind NbItems, Converter={StaticResource StringFormatConverter}, ConverterParameter='FORMAT', Mode=OneWay}" />
Finally change your converter to load the the resource using the parameter like so:
public object Convert(object value, Type targetType, object parameter, string language) {
if (value == null)
return null;
var loader = new Windows.ApplicationModel.Resources.ResourceLoader();
var str = loader.GetString((string)parameter);
return string.Format(str, value);
}
Hope this helps.

Related

WPF Treeview use property value as Binding Path

I'm trying to create a Treeview using an ObservableCollection of a custom class called MachineComponentFault, which includes a string property called FaultText, and I'd like to make the text localized.
I'm using WPF Runtime Localization from Codeproject to localize texts at runtime, and it usually works as follows:
<TextBlock Text="{Binding Path=NameInResources, Source={StaticResource Resources}}"/>
The problem is that I can't seem to figure out how to set the value of the property to the path, so that it can retrieve the translation. This is what I managed thus far:
<TreeView Name="myTreeView" VirtualizingPanel.IsVirtualizing="True" ItemsSource="{Binding Faults}">
<TreeView.Resources>
<DataTemplate DataType="{x:Type MassComponents:MachineComponentFault}">
<StackPanel Orientation="Horizontal" >
<TextBlock Name="Text1" Text="{Binding FaultText}"/>
<TextBlock Name="Text2" Text="{Binding Path=FLT_PTC_1, Source={StaticResource Resources}}"/>
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
Essentially Text1 shows FLT_PTC_1 at Runtime, while Text2 shows "Motor Overheat", which is the value of FLT_PTC_1 in Resources.resx (which can be translated). The issue is that I can't seem to be able to do what Text2 does using FaultText Property.
Is there a way to do it?
EDIT:
Solved it using mm8 solution, while maintaining the WPF Runtime Localization. The solution isn't pretty at all, since it consists in creating a Binding on a dummy class and then retrieving the binding value as a string, which seems a bit convoluted, but it's the best solution I could find.
public class ResourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string resourceName = value as string;
if (!string.IsNullOrEmpty(resourceName)) //look up the resource here:
{
Binding b = new Binding(resourceName); //Create Binding using as Path the value of FaultText
b.Source = CultureResources.ResourceProvider; //Get the resources from WPF Runtime Localization ObjectDataProvider
BindingOperations.SetBinding(_dummy, Dummy.ValueProperty, b); //Set the Binding to the dummy class instance
return _dummy.GetValue(Dummy.ValueProperty); //Retrieve the value of the Binding from the dummy class instance and return it
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
//Initialize Dummy class
private static readonly Dummy _dummy = new Dummy();
//Create a dummy class that accepts the Binding
private class Dummy : DependencyObject
{
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(object), typeof(Dummy), new UIPropertyMetadata(null));
}
}
XAML same as mm8 proposed.
You could bind to the FaultText property and use a converter to look up the resource. Something like this:
public class ResourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string resourceName = value as string;
if (!string.IsNullOrEmpty(resourceName)) //look up the resource here:
return Resource1.ResourceManager.GetString(resourceName);
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML:
<TextBlock Name="Text2">
<TextBlock.Text>
<Binding Path="FaultText">
<Binding.Converter>
<local:ResourceConverter />
</Binding.Converter>
</Binding>
</TextBlock.Text>
</TextBlock>

C# ConvertBack from a binding column of textbox to a JObject

GoodDay!
I'm not good with wpf and binding, i need your help. I have already bind a Json Object (JObject) to a Column of TextBox.
<TextBox Width="250" Text="{Binding Path=Property, Converter={StaticResource jPropertyConverter}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
I can show properly the data of the Jobject when i start my wpf window, now i need to ConvertBack the data modified when i modify one of the textbox of the columns, from that TextBox to the JObject, and the related JValue.
public class JPropertyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is JProperty)
{
JToken valoreProperty = (value as JProperty).Value;
if ((valoreProperty is JValue))
return (valoreProperty as JValue).Value;
}
return DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
??
}
}
I can change the Value of the "leaves" of this JObject tree like:
(valoreProperty as JValue).Value = "Hello!";
How can i change the "leaves" of this JObject tree in the convert back?
Sorry for my english.
Thanks and bye
EDIT:
Thanks dbc! It works, many thanks!
Now i need to show in another column, every lenght of the value inside of the textbox, obviously if i change the value in the texbox the relative lenght value will change too.
I tried:
<DataGridTextColumn Header="Lunghezza2" IsReadOnly="True" Width="50" Binding="{Binding Path=Property.Value.Value.toString().Length, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}" />
or in another way with a converter, passing a JProperty
public class LengthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is JProperty)
{
JToken jValue = (value as JProperty).Value;
if ((jValue is JValue) && (jValue as JValue).Value != null)
return (jValue as JValue).Value.ToString().Length.ToString();
else
return "0";
}
else
return "";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
But every try didn't works when i change the textbox value, any tips?
Many thanks again!
You don't need a converter for this purpose. Assuming your Property property returns a JProperty, you can bind directly to JProperty.Value.Value
<TextBox Name="PropertyTextBox"
Text="{Binding Path=Property.Value.Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
/>
If you want to disable the TextBox if the bound Property is not a "simple" JProperty (one with just a JValue for its value), you can do:
<TextBox Name="PropertyTextBox"
Text="{Binding Path=Property.Value.Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding Path=Property, Converter={StaticResource IsSimpleJPropertyConverter}, Mode=OneWay}"
/>
Using the converter
public class IsSimpleJPropertyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is JProperty)
{
JToken jValue = (value as JProperty).Value;
if (jValue is JValue)
return true;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

How to bind 2 textboxes to one property?

I have a propery PhoneNumber and in the UI, I have 2 textboxes, one is the prefix, and the other one is the postfix, how can I bind it to the property? (The property inside the DataContext).
<TextBox Grid.Column="0" MaxLength="3" /> //Prefix
<TextBlock Grid.Column="1" Text="-" />
<TextBox Grid.Column="2" /> //Postfix
The only way I see it work is with code behind using textbox1.Text + textbox2.Text... Is there a better way?
Thanks in advance :)
Just use two more properties in the data context
code is not complied or tested
public string PhoneNumber { get; set; }
public string Prefix
{
get
{
return PhoneNumber.Substring(0, 3);
}
set
{
// replace the first three chars of PhoneNumber
PhoneNumber = value + PhoneNumber.Substring(3);
}
}
public string Postfix
{
get
{
return PhoneNumber.Substring(3);
}
set
{
// replace the chars of starting from index 3 of PhoneNumber
PhoneNumber = PhoneNumber.Substring(0, 3) + value;
}
}
I think uou can use Converter for this purpose, the example going one way can look like this:
In this my Number is a string 000-000000, but you can surely change it.
In XAML:
<Window.Resources>
<conv:PostixConverter x:Key="PostfixConv" xmlns:conv="clr-namespace:Example.Converters"/>
<conv:PrefixConverter x:Key="PrefixConv" xmlns:conv="clr-namespace:Example.Converters"/>
</Window.Resources>
<StackPanel>
<TextBox MaxLength="3" Text="{Binding Number, Converter={StaticResource PrefixConv}}"/>
<TextBlock Text="-" />
<TextBox Text="{Binding Number, Converter={StaticResource PostfixConv}}"/>
</StackPanel>
And in code behind:
namespace Example.Converters
{
public class PrefixConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null) return null;
else return ((string)value).Substring(0, 3);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class PostixConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null) return null;
else return ((string)value).Substring(4);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

How to pass a static value to IValueConverter in XAML

I would like to use static texts fetched from a web service in my WP7 app. Each text has a Name (the indetifier) and a Content property.
For example a text could look like this:
Name = "M43";
Content = "This is the text to be shown";
I would then like to pass the Name (i.e. the identifier) of the text to an IValueConverter, which would then look up the the Name and return the text.
I figured the converter to look something like this:
public class StaticTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
return App.StaticTexts.Items.SingleOrDefault(t => t.Name.Equals(value)).Content;
}
return null;
}
}
Then in the XAML:
<phone:PhoneApplicationPage.Resources>
<Helpers:StaticTextConverter x:Name="StaticTextConverter" />
</phone:PhoneApplicationPage.Resources>
...
<TextBlock Text="{Binding 'M43', Converter={StaticResource StaticTextConverter}}"/>
However, this does not seem to work and I am not sure that I pass in the value to the converter correctly.
Does anyone have some suggestions?
I finally found the answer. The answer was a mix between that of #Shawn Kendrot and another question I asked here: IValueConverter not getting invoked in some scenarios
To summarize the solution for using the IValueConverter I have to bind my control in the following manor:
<phone:PhoneApplicationPage.Resources>
<Helpers:StaticTextConverter x:Name="TextConverter" />
</phone:PhoneApplicationPage.Resources>
<TextBlock Text="{Binding Converter={StaticResource TextConverter}, ConverterParameter=M62}" />
Since the ID of the text is passed in with the converter parameter, the converter looks almost the same:
public class StaticTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (parameter != null && parameter is string)
{
return App.StaticTexts.Items.SingleOrDefault(t => t.Name.Equals(parameter)).Content;
}
return null;
}
}
However, as it turns out, the binding and thus the converter is not invoked if it does not have a DataContext. To solve this, the DataContext property of the control just has to be set to something arbitrary:
<TextBlock DataContext="arbitrary"
Text="{Binding Converter={StaticResource TextConverter}, ConverterParameter=M62}" />
And then everything works as intended!
The problem lies in your binding. It will check the DataContext, and on this object, it will try to evaluate the properties M62 and ValueboxConsent on that object.
You might want to add static keys somewhere in your application where you can bind to:
<TextBlock Text="{Binding Source="{x:Static M62.ValueboxConsent}", Converter={StaticResource StaticTextConverter}}" />
Where M62 is a static class where your keys are located.. like so:
public static class M62
{
public static string ValueboxConsent
{
get { return "myValueBoxConsentKey"; }
}
}
If you want to use a value converter, you'll need to pass the string to the parameter of value converter
Xaml:
<TextBlock Text="{Binding Converter={StaticResource StaticTextConverter}, ConverterParameter=M43}"/>
Converter:
public class StaticTextConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (parameter != null)
{
return App.StaticTexts.Items.SingleOrDefault(t => t.Name.Equals(parameter)).Content;
}
return null;
}
}
xmlns:prop="clr-namespace:MyProj.Properties;assembly=namespace:MyProj"
<TextBlock Text="{Binding Source={x:Static prop:Resources.MyString}, Converter={StaticResource StringToUpperCaseConverter}}" />

Cannot make converter work

I am trying to learn how to use IValueConverter. I have the following converter:
[ValueConversion(typeof(string), typeof(string))]
public class RequiredFieldConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return "";
return value.ToString() + "*";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return "";
var str = value.ToString();
return str+"Convert Back testing";
}
}
I have added the RequiredFieldConverter resource in my app.xaml file and I want to try it as:
<TextBox Name="textBox2" Width="120" />
<TextBox Text="{Binding ElementName=textBox2, Path=Text, Converter=RequiredFieldConverter}" Name="textBox3" Width="120" />
I was hoping that when I type "hello" in textbox2 it shows "hello*" in textbox3 but it does not work. In fact I get the following exception at runtime:
{"Unable to cast object of type 'System.String' to type 'System.Windows.Data.IValueConverter'."}
also I know that the value converter function is working because it works when I do:
Content="{Binding Source={StaticResource Cliente}, Converter={StaticResource RequiredFieldConverter}}"
... You are getting the error as it trying to interpret RequiredFieldConverter as an reference to an IValueConverter. You need to use a StaticResource or DynamicResource to reference the converter as you have done in your second example.
<TextBox Text="{Binding ElementName=textBox2, Path=Text, Converter={StaticResouce RequiredFieldConverter}}" Name="textBox3" Width="120" />

Categories

Resources