I'm creating an application that will be build in modules (DLL's). One of these DLL's provides the Strings for the application in different languages.
The DLL has following structure:
Languages (This is the project.)
Properties
References
Language.cs (Here I'm able to set the desired language from the application and has a GetText function that returns the String based on the set Culture.) Please let me know is this is a good approach.
Language.en-US.resx
Language.nl-BE.resx
So, from Languages.cs I'm able to get the desired String in C# from the resource files based on the set Culture.
Here is an example:
I set the culture to Dutch: Languages.Language.SetCulture("nl-BE");
I request the Dutch word for the resource Name: Language.GetText("Name");
It will return the String Naam.
That was C#. Xaml appears to be a bigger problem to get a Label.Text get the resource Name.
I added xmlns:l="clr-namespace:My.Languages.;assembly=My.Languages" to my xaml file, but this is as far as I got. I can't figure out a way how to have a similar Language.GetText("Name") in Binding.
My only solution at this point would be to bind every Label.Text to a property in my C# code and get the correct String from there. This will generate a lot of "not needed" binding/properties and would be hard to maintain.
Any suggestions?
My approach for Xaml would be to use a Converter that would call your Language.GetText(key);
e.g. XAML
<TextBlock Text={Binding FallbackValue='Naam', ConverterParameter='Name' Converter={StaticResource Translate}}" />
C#
public class TranslateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
return DependencyProperty.UnsetValue;
string localizedValue = string.Empty;
if (parameter is string)
{
localizedValue = Language.GetText(parameter as string);
return localizedValue;
}
else
{
return DependencyProperty.UnsetValue;
}
}
}
Related
I have a WinUI 3 app where we use Dependency-Injection from Microsoft.Extensions, and settings containing DateTime the current Date-Time formatting have been registered to the service collection as followed:
services.AddSingleton<IDateFormatService, DateFormatService>();
I'd like to just inject it into the constructor of the IValeConverter, but as it is constructed by the XAML the constructor must be empty.
Below is my current converter
public sealed class DateTimeFormatingConverter : DependencyObject, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value is not DateTime dateTime)
return value;
// return formatted dateTime based on settings formatting string
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
I know other injection libraries can allow this, as I've seen in this post and there for wondered if a likewise solution exist with the Microsoft extensions version.
I know it's a possibility to make a DependencyProperty and in XAML bind it to the dependency injected property in the viewmodel. However im looking into this as it would clean up the code substantially and while also removed multiple requirements from the converter that another developer won't easily know would be required.
I'd like to just inject it into the constructor of the IValeConverter, but as it is constructed by the XAML the constructor must be empty.
Correct.
The XAML processor engine doesn't know how to use Microsoft.Extensions to resolve dependencies so if you want to inject your converter with a constructor dependency that you register yourself, you must construct the converter programmatically (and not define it in the XAML markup).
You could for example do this in App.xaml.cs after you have registered the dependencies, e.g.:
this.Resources.Add("myConverter",
services.GetRequiredService<DateTimeFormatingConverter>());
UWP allows you to bind to a static method. I'm trying to get a time string by using
<TextBlock Text={x:Bind MyDateTime.ToString(MyPatternString)} />
where MyPatternString is "h:mm tt".
The problem is that DateTime's ToString() method has several different signatures. The first one receives an IFormatProvider. Because of this, I get a build error:
Function parameter 'provider' is invalid or missmatched
Is there any way to tell it that I wish to use the signature which accepts a string? I'd have thought it would automatically know this.
You can just add a method to your ViewModel and use that instead!
That way your binding expression can be changed to this:
<TextBlock Text={x:Bind FormatDateToString(MyDateTime)} />
Be advised that this works with the Windows 10 Anniversary Update only! More info on this matter here!
Found your question after searching for the answer myself; didn't find much help posted anywhere but did figure it out after some trial and error.
Function parameter 'provider' is invalid or mismatched
The reason for this that in XAML, a specific overload is being called which is DateTimeProperty.ToString(string, IFormatProvider).
In my case, any value I display is within a User Control so for each I added a CultureInfo dependency property and bound it to common source on my view model.
If C#, add:
using System.Globalization;
Then
public static readonly DependencyProperty CultureInfoProperty = DependencyProperty.Register(
"CultureInfo", typeof(CultureInfo), typeof(XyzReadoutView), new PropertyMetadata(default(CultureInfo)));
public CultureInfo CultureInfo
{
get { return (CultureInfo) GetValue(CultureInfoProperty); }
set { SetValue(CultureInfoProperty, value); }
}
This creates a local instance required for x:Bind, compile errors occur if using a static property.
And XAML:
<TextBlock Text={x:Bind MyDateTime.ToString('h:mm tt', CultureInfo)} />
Notice the format is surrounded with ' and not ".
Also, this will only update once as the mode for x:Bind has a default of Mode=OneTime; if you want changes on the DateTime or CultureInfo to propagate, the mode must be changed to Mode=OneWay.
<TextBlock Text={x:Bind MyDateTime.ToString('h:mm tt', CultureInfo), Mode=OneWay} />
If the format is user changeable, I would create a dependency property for it as well for updates and easy control binding back to a view model but that's just my personal preference.
public static readonly DependencyProperty DateTimeFormatProperty = DependencyProperty.Register(
"DateTimeFormat", typeof(string), typeof(XyzReadoutView), new PropertyMetadata(default(string)));
public string DateTimeFormat
{
get { return (string) GetValue(DateTimeFormatProperty); }
set { SetValue(DateTimeFormatProperty, value); }
}
And XAML:
<TextBlock Text={x:Bind MyDateTime.ToString(DateTimeFormat, CultureInfo), Mode=OneWay} />
You need to use an IValueConverter to format the text for display. Create a class which inherits from IValueConverter.
public class DateFormatter : IValueConverter
{
// This converts the DateTime object to the string to display.
public object Convert(object value, Type targetType,
object parameter, string language)
{
// Retrieve the format string and use it to format the value.
string formatString = parameter as string;
if (!string.IsNullOrEmpty(formatString))
{
return string.Format(
new CultureInfo(language), formatString, value);
}
// If the format string is null or empty, simply call ToString()
// on the value.
return value.ToString();
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
}
Register it as resource on the Page and then you can specify the converter in the binding
<TextBlock Text={x:Bind MyDateTime, Converter={StaticResource DateFormatConverter}}, ConverterParameter="mm/dd/yyyy"}"/>
https://learn.microsoft.com/en-us/uwp/api/Windows.UI.Xaml.Data.IValueConverter
I am trying to format my string to have commas every 3 places, and a decimal if it is not a whole number. I have checked roughly 20 examples, and this is the closest I have come:
<TextBlock x:Name="countTextBlock" Text="{Binding Count, StringFormat={0:n}}" />
But I get a The property 'StringFormat' was not found in type 'Binding'. error.
Any ideas what is wrong here? Windows Phone 8.1 appears to differ from WPF, because all of the WPF resources say that this is how it is done.
(The string is updated constantly, so I need the code to be in the XAML. I also need it to remain binded. Unless of course I cannot have my cake and eat it too.)
It seems that, similar to Binding in WinRT, Binding in Windows Phone Universal Apps doesn't have StringFormat property. One possible way to work around this limitation is using Converter as explained in this blog post,
To summarize the post, you can create an IValueConverter implmentation that accept string format as parameter :
public sealed 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();
}
}
Create a resource of above converter in your XAML, then you can use it like this for example :
<TextBlock x:Name="countTextBlock"
Text="{Binding Count,
Converter={StaticResource StringFormatConverter},
ConverterParameter='{}{0:n}'}" />
i playing around with the new Windows Store Universal App template which could be used for Windows 8.1 and Windows Phone 8.1 and was wondering how to format strings in XAML code.
What i tried (XAML):
<TextBlock Text="{Binding TestItem.CurrentDate, StringFormat={}{0:MM/dd/yyyy}}" />
The problem is that StringFormat is not available in Windows.UI.Xaml.Controls.TextBox.
Microsoft has created a sample project which is all about formatting dates. But the approach used there is based on (ugly) code behind.
So, here is my Question:
Why is StringFormat not available in Windows Store Universal Apps?
How do i format strings using XAML Code only?
EDIT:
I decided to go with the converter solution, for those of interest here is the code:
public class DateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
return null;
if (!(value is DateTime))
return null;
var dateTime = (DateTime)value;
var dateTimeFormatter = new DateTimeFormatter(YearFormat.Full,
MonthFormat.Full,
DayFormat.Default,
DayOfWeekFormat.None,
HourFormat.None,
MinuteFormat.None,
SecondFormat.None,
new[] { "de-DE" },
"DE",
CalendarIdentifiers.Gregorian,
ClockIdentifiers.TwentyFourHour);
return dateTimeFormatter.Format(dateTime);
}
public object ConvertBack(object value, Type targetType, object parameter,
string language)
{
throw new NotImplementedException();
}
}
I'm happy for every single advice how to improve the code above, feel free to comment.
Thank you Mikael DĂși Bolinder and Martin Suchan for your suggestion/answer.
DataBinding in Windows Runtime project types does not support StringFormat property, the options you have are:
Use already formatted date as a get-only property in your ViewModel.
Use Converter - you can even create StringFormatConverter where you can pass the DateTime format as ConverterParameter. Here's a solution how such StringFormatConverter could work.
Let me start out by saying I have tried this and looked at this (which just leads to the first one). Those are great solutions for WPF. As we all are getting to know, the Windows Phone 7 is missing some of the nice edge cases.
My project seems to be destined to be devoid of dynamic images. I have an tag that I am trying to bind to a resource file and it is not working. I have tried both of the following, and neither seem to work.
First, the ever popular converter. Takes the URI string and returns a bitmap image. Apparently it works in WPF, but I can't make it work.
public class BitmapImageConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
try
{
return new BitmapImage(new Uri((string)value));
}
catch
{
return new BitmapImage();
}
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then there is the BitmapImage property. Didn't really expect this one to work and it didn't disappoint.
public BitmapImage ImgSource
{
get
{
// ImgURI is a URI to the image.
BitmapImage newImg = new BitmapImage(new Uri(ImgURI));
// Tried ALL the creation options. :(
//newImg.CreateOptions = BitmapCreateOptions.None;
return newImg;
}
}
This is the XAML I am using for the converter (which is defined elsewhere) is....
<Image Name="imgMap"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Source="{Binding ImgURI, Mode=OneWay, Converter={StaticResource bitmapConverter}}"
Stretch="None"/>
I have debugged it to the point that I know that each binding is returning what it is supposed to. The converter is called and does what I think it should. ImgURI always returns a string of the format "/MyNamespace;component/Images/MyImg.jpg" and ImgSource was always a bitmapImage. All images have a BuildAction of "Resource".
I hope I am missing something obvious. Thanks for looking at my issue and if further information is needed, please leave a comment.
You should be using the Build Action of Content not Resource.
I doubt this is your problem, but make sure you're passing UriKind.Relative to the Uri constructor.