I am trying to make my WPF app support two languages.. but I'm facing an issue when trying to bind DataTime
DP to a TextBlock
inside a UserControl
and changing the current culture at runtime.
The DateTime
format doesn't change to the updated Culture rather it only changes when restarting the app then stay static.
My Code:
App.xaml.cs
public App()
{
CultureInfo CultureInformation = new CultureInfo("en-UK");
CultureInformation.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
CultureInformation.DateTimeFormat.LongDatePattern = "ddd, dd/MM/yyyy";
CultureInfo.DefaultThreadCurrentCulture = CultureInformation;
CultureInfo.DefaultThreadCurrentUICulture = CultureInformation;
}
MainWindow.xaml.cs
private void UpdateLanguage(string Language)
{
LanguageComboBox.SelectedValue = Properties.Settings.Default.Language = Language;
Properties.Settings.Default.Save();
//
ResourceDictionary Dictionary = new();
Dictionary.Source = new Uri(@$"..\Languages\{Language}.xaml", UriKind.Relative);
Resources.MergedDictionaries.Clear();
Resources.MergedDictionaries.Add(Dictionary);
//
if (Language == "العربية")
{
CultureInfo CultureInformation = CultureInfo.CreateSpecificCulture("ar-EG");
CultureInformation.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
CultureInformation.DateTimeFormat.LongDatePattern = "ddd, dd/MM/yyyy";
Thread.CurrentThread.CurrentCulture = CultureInformation;
Thread.CurrentThread.CurrentUICulture = CultureInformation;
}
else if (Language == "English")
{
CultureInfo CultureInformation = CultureInfo.CreateSpecificCulture("en-UK");
CultureInformation.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
CultureInformation.DateTimeFormat.LongDatePattern = "ddd, dd/MM/yyyy";
Thread.CurrentThread.CurrentCulture = CultureInformation;
Thread.CurrentThread.CurrentUICulture = CultureInformation;
}
}
ConverterCulture
public class CultureAwareBinding : Binding
{
public CultureAwareBinding()
{
ConverterCulture = CultureInfo.CurrentCulture;
}
}
UserControl.xaml
<TextBlock Grid.Row="5" FontSize="14" FontFamily="{StaticResource Segoe Semibold}" Foreground="{DynamicResource BackgroundBrush}">
<TextBlock Text="{local:CultureAwareBinding Path=StartTime, StringFormat={}{0:hh:mm tt}}"/>
<TextBlock Text="" FontSize="12" FontFamily="{StaticResource Segoe Icons}"/>
<TextBlock Text="{local:CultureAwareBinding Path=EndTime, StringFormat={}{0:hh:mm tt}}"/>
</TextBlock>
Thanks in advance.
CodePudding user response:
You may need to notify your WPF form controls. just require raising PropertyChanged for CurrentCulture here's an example
CodePudding user response:
Unfortunately, there is no ready-made simple solution that can be applied to all cases.
The decision depends on what you think is valid for its implementation and how you have implemented the bindings.
- Let's say you have all the bindings to the Window data context.
And in fact you need to call the rendering of the DataContext view on all Windows.
Then you can use this method in Code Behind App:
public static async void RerenderAllDataContext()
{
var windows = Current.Windows.OfType<Window>().ToList();
var dataContextes = windows.ToDictionary(w => w, w => w.DataContext);
var dispatcher = Current.Dispatcher;
await dispatcher.InvokeAsync(() => windows.ForEach(w => w.DataContext = null));
await dispatcher.InvokeAsync(() => windows.ForEach(w => w.DataContext = dataContextes[w]));
}
But this method has its drawbacks: it redraws all windows, the state of UI elements is reset (for example, the cursor position in the TextBox or SelectedItem), there may be bindings not to the Data Context, etc.
- If there are not many bindings for which you need to take into account the culture, or they are created not only to the Data Context, then all that remains is to call the redrawing of all such bindings.
With minimal changes, this can be done by using MiltiBinding instead of Binding, in which one of the bindings (usually the last one) will use the property with the current culture.
For such a MiltiBinding, the converter returns the first value of the received array of values (if there are two of them).
For simplicity's sake, you can derive a class from MiltiBinding to approximate its application as closely as possible to a regular Binding.