在 WPF .net core 5 中运行时更改应用程序区域性时如何更新 属性 绑定
How to update property binding when changing the culture of the application at runtime in WPF .net core 5
我试图让我的 WPF 应用程序支持两种语言..但是当我尝试将 DataTime
DP 绑定到 UserControl
中的 TextBlock
时我遇到了问题并且在运行时更改当前区域性。
DateTime
格式不会更改为更新后的文化,而只会在重新启动应用程序时更改,然后保持静态。
我的代码:
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>
提前致谢。
您可能需要通知您的 WPF 表单控件。只需要为 CurrentCulture 提高 PropertyChanged
这是一个 example
遗憾的是,没有现成的简单解决方案可以适用于所有情况。
该决定取决于您认为对其实施有效的内容以及您如何实施绑定。
- 假设您拥有 Window 数据上下文的所有绑定。
事实上,您需要在所有 Windows.
上调用 DataContext 视图的呈现
那么你可以在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]));
}
但是这个方法有它的缺点:它重绘了所有windows,UI元素的状态被重置(例如,光标在TextBox或SelectedItem中的位置),可能有绑定不是数据上下文等
- 如果您需要考虑文化的绑定不多,或者它们不仅是为数据上下文创建的,那么剩下的就是调用所有此类绑定的重绘。
通过使用 MiltiBinding 而不是 Binding 进行最小的更改,这可以完成,其中一个绑定(通常是最后一个)将使用具有当前文化的 属性。
对于这样的 MiltiBinding,转换器 returns 接收到的值数组的第一个值(如果有两个)。
为简单起见,您可以从 MiltiBinding 派生一个 class 以使其应用程序尽可能接近常规绑定。
以另一种方式补充答案:
- 可以使用FrameworkElement.Language属性设置文化。
这是一个依赖项 属性 所以你可以绑定它。
属性 值由子项继承(类似于 DataContext)。
如果将它设置为 Window,那么其中的所有元素也将取相同的值。
或者您可以将其设置为某个特定元素。
可以声明其他类型以减少 XAML 代码。
例子.
静态 class 用于全局设置文化:
using System;
using System.Windows.Markup;
namespace Wpf.Data
{
public static class LanguageAware
{
public static XmlLanguage CurrentLanguage { get; private set; } = XmlLanguage.Empty;
public static event EventHandler CurrentLanguageChanged;
public static void SetCurrentLanguage(XmlLanguage currentLanguage)
{
if (currentLanguage == null)
{
currentLanguage = XmlLanguage.Empty;
}
if (!Equals(CurrentLanguage, currentLanguage))
{
CurrentLanguage = currentLanguage;
CurrentLanguageChanged?.Invoke(null, EventArgs.Empty);
}
}
}
}
使用示例:
<Window.Resources>
<sys:DateTime x:Key="date">12.31.2021 15:47</sys:DateTime>
</Window.Resources>
<UniformGrid Columns="1">
<TextBlock Text="{Binding Path=(wpfdata:LanguageAware.CurrentLanguage)}" />
<TextBox Text="{Binding Mode=OneWay, Source={StaticResource date}, StringFormat=\{0:F\}}"
Language="{Binding Path=(wpfdata:LanguageAware.CurrentLanguage)}"/>
<TextBox Text="{Binding Mode=OneWay, Source={StaticResource date}, StringFormat=\{0:F\}}"/>
<Button Content="Russian" Click="OnCultureClick" CommandParameter="RU" Margin="10"/>
<Button Content="English-USA" Click="OnCultureClick" CommandParameter="En-Us" Margin="10"/>
</UniformGrid>
<x:Code><![CDATA[
private void OnCultureClick(object sender, RoutedEventArgs e)
{
string lang = ((Button)sender).CommandParameter as string;
if (lang == null)
LanguageAware.SetCurrentLanguage(null);
else
LanguageAware.SetCurrentLanguage(XmlLanguage.GetLanguage(lang));
}]]>
</x:Code>
用命令替换 XAML 中的答题器的标记扩展:
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Threading;
namespace Wpf.Data
{
[MarkupExtensionReturnType(typeof(ICommand))]
public class LanguageCommandExtension : MarkupExtension
{
private static readonly LanguageCommand command = new LanguageCommand();
public void RaiseCanExecuteChanged() => command.RaiseCanExecuteChanged();
public override object ProvideValue(IServiceProvider serviceProvider)
{
return command;
}
private class LanguageCommand : ICommand
{
private readonly EventHandler requerySuggested;
/// <inheritdoc cref="ICommand.CanExecuteChanged"/>
public event EventHandler CanExecuteChanged;
private static readonly Dispatcher dispatcher = Application.Current.Dispatcher;
/// <summary> The method that raises the event <see cref="CanExecuteChanged"/>.</summary>
public void RaiseCanExecuteChanged()
{
if (dispatcher.CheckAccess())
{
invalidate();
}
else
{
_ = dispatcher.BeginInvoke(invalidate);
}
}
private readonly Action invalidate;
public LanguageCommand()
{
invalidate = () => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
requerySuggested = (o, e) => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
CommandManager.RequerySuggested += requerySuggested;
}
/// <inheritdoc cref="ICommand.CanExecute(object)"/>
public bool CanExecute(object parameter)
{
if (parameter == null || parameter is XmlLanguage)
{
return true;
}
try
{
if (parameter is string str)
{
return XmlLanguage.GetLanguage(str) != null;
}
if (parameter is CultureInfo culture)
{
str = culture.Name;
return XmlLanguage.GetLanguage(str) != null;
}
}
catch (Exception)
{ }
return false;
}
/// <inheritdoc cref="ICommand.Execute(object)"/>
public void Execute(object parameter)
{
if (parameter is XmlLanguage language)
{ }
else if (parameter == null)
{
language = null;
}
else
{
try
{
if (parameter is string str)
{
language = XmlLanguage.GetLanguage(str);
}
else if (parameter is CultureInfo culture)
{
str = culture.Name;
language = XmlLanguage.GetLanguage(str);
}
else
{
throw new InvalidCastException(nameof(parameter));
}
}
catch (Exception)
{
throw new ArgumentException(nameof(parameter));
}
}
LanguageAware.SetCurrentLanguage(language);
}
}
}
}
设置面板语言的示例:
<Window.Resources>
<sys:DateTime x:Key="date">12.31.2021 15:47</sys:DateTime>
</Window.Resources>
<UniformGrid Columns="1"
Language="{Binding Path=(wpfdata:LanguageAware.CurrentLanguage)}">
<TextBlock Text="{Binding Path=(wpfdata:LanguageAware.CurrentLanguage)}" />
<TextBox Text="{Binding Mode=OneWay, Source={StaticResource date}, StringFormat=\{0:F\}}"/>
<TextBox Text="{Binding Mode=OneWay, Source={StaticResource date}, StringFormat=\{0:F\}}"/>
<Button Content="Russian" Command="{wpfdata:LanguageCommand}" CommandParameter="RU" Margin="10"/>
<Button Content="English-USA" Command="{wpfdata:LanguageCommand}" CommandParameter="En-Us" Margin="10"/>
</UniformGrid>
语言的标记扩展 属性:
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
namespace Wpf.Data
{
[MarkupExtensionReturnType(typeof(Binding))]
public class LanguageAwareExtension : Binding
{
public LanguageAwareExtension()
{
Path = new PropertyPath(
"(0)",
typeof(LanguageAware).GetProperty(nameof(LanguageAware.CurrentLanguage)));
ConverterCulture = CultureInfo.CurrentCulture;
}
}
}
设置Window语言的示例:
<Window ----------------------------
----------------------------
Language="{wpfdata:LanguageAware}">
<Window.Resources>
<sys:DateTime x:Key="date">12.31.2021 15:47</sys:DateTime>
</Window.Resources>
<UniformGrid Columns="1">
<TextBlock Text="{Binding Path=(wpfdata:LanguageAware.CurrentLanguage)}" />
<TextBox Text="{Binding Mode=OneWay, Source={StaticResource date}, StringFormat=\{0:F\}}"/>
<TextBox Text="{Binding Mode=OneWay, Source={StaticResource date}, StringFormat=\{0:F\}}"/>
<Button Content="Russian" Command="{wpfdata:LanguageCommand}" CommandParameter="RU" Margin="10"/>
<Button Content="English-USA" Command="{wpfdata:LanguageCommand}" CommandParameter="En-Us" Margin="10"/>
</UniformGrid>
</Window>
答案
App.xaml.cs
public App()
{
CultureInfo CultureInformation = new CultureInfo("en-US");
CultureInformation.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
CultureInformation.DateTimeFormat.LongDatePattern = "ddd, dd/MM/yyyy";
CultureInfo.DefaultThreadCurrentCulture = CultureInformation;
CultureInfo.DefaultThreadCurrentUICulture = CultureInformation;
//
XmlLanguage language = XmlLanguage.GetLanguage(CultureInformation.IetfLanguageTag);
const BindingFlags kField = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
typeof(XmlLanguage).GetField("_equivalentCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_compatibleCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_specificCulture", kField).SetValue(language, CultureInformation);
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(language));
}
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;
//
XmlLanguage language = XmlLanguage.GetLanguage(CultureInformation.IetfLanguageTag);
const BindingFlags kField = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
typeof(XmlLanguage).GetField("_equivalentCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_compatibleCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_specificCulture", kField).SetValue(language, CultureInformation);
this.Language = language;
}
else if (Language == "English")
{
CultureInfo CultureInformation = CultureInfo.CreateSpecificCulture("en-US");
CultureInformation.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
CultureInformation.DateTimeFormat.LongDatePattern = "ddd, dd/MM/yyyy";
Thread.CurrentThread.CurrentCulture = CultureInformation;
Thread.CurrentThread.CurrentUICulture = CultureInformation;
//
XmlLanguage language = XmlLanguage.GetLanguage(CultureInformation.IetfLanguageTag);
const BindingFlags kField = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
typeof(XmlLanguage).GetField("_equivalentCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_compatibleCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_specificCulture", kField).SetValue(language, CultureInformation);
this.Language = language;
}
}
有没有 ConverterCulture class
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="{Binding Path=StartTime, StringFormat={}{0:hh:mm tt}}"/>
<TextBlock Text="" FontSize="12" FontFamily="{StaticResource Segoe Icons}"/>
<TextBlock Text="{Binding Path=EndTime, StringFormat={}{0:hh:mm tt}}"/>
</TextBlock>
我试图让我的 WPF 应用程序支持两种语言..但是当我尝试将 DataTime
DP 绑定到 UserControl
中的 TextBlock
时我遇到了问题并且在运行时更改当前区域性。
DateTime
格式不会更改为更新后的文化,而只会在重新启动应用程序时更改,然后保持静态。
我的代码:
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>
提前致谢。
您可能需要通知您的 WPF 表单控件。只需要为 CurrentCulture 提高 PropertyChanged 这是一个 example
遗憾的是,没有现成的简单解决方案可以适用于所有情况。
该决定取决于您认为对其实施有效的内容以及您如何实施绑定。
- 假设您拥有 Window 数据上下文的所有绑定。
事实上,您需要在所有 Windows.
上调用 DataContext 视图的呈现 那么你可以在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]));
}
但是这个方法有它的缺点:它重绘了所有windows,UI元素的状态被重置(例如,光标在TextBox或SelectedItem中的位置),可能有绑定不是数据上下文等
- 如果您需要考虑文化的绑定不多,或者它们不仅是为数据上下文创建的,那么剩下的就是调用所有此类绑定的重绘。
通过使用 MiltiBinding 而不是 Binding 进行最小的更改,这可以完成,其中一个绑定(通常是最后一个)将使用具有当前文化的 属性。
对于这样的 MiltiBinding,转换器 returns 接收到的值数组的第一个值(如果有两个)。
为简单起见,您可以从 MiltiBinding 派生一个 class 以使其应用程序尽可能接近常规绑定。
以另一种方式补充答案:
- 可以使用FrameworkElement.Language属性设置文化。 这是一个依赖项 属性 所以你可以绑定它。 属性 值由子项继承(类似于 DataContext)。 如果将它设置为 Window,那么其中的所有元素也将取相同的值。 或者您可以将其设置为某个特定元素。
可以声明其他类型以减少 XAML 代码。
例子.
静态 class 用于全局设置文化:
using System;
using System.Windows.Markup;
namespace Wpf.Data
{
public static class LanguageAware
{
public static XmlLanguage CurrentLanguage { get; private set; } = XmlLanguage.Empty;
public static event EventHandler CurrentLanguageChanged;
public static void SetCurrentLanguage(XmlLanguage currentLanguage)
{
if (currentLanguage == null)
{
currentLanguage = XmlLanguage.Empty;
}
if (!Equals(CurrentLanguage, currentLanguage))
{
CurrentLanguage = currentLanguage;
CurrentLanguageChanged?.Invoke(null, EventArgs.Empty);
}
}
}
}
使用示例:
<Window.Resources>
<sys:DateTime x:Key="date">12.31.2021 15:47</sys:DateTime>
</Window.Resources>
<UniformGrid Columns="1">
<TextBlock Text="{Binding Path=(wpfdata:LanguageAware.CurrentLanguage)}" />
<TextBox Text="{Binding Mode=OneWay, Source={StaticResource date}, StringFormat=\{0:F\}}"
Language="{Binding Path=(wpfdata:LanguageAware.CurrentLanguage)}"/>
<TextBox Text="{Binding Mode=OneWay, Source={StaticResource date}, StringFormat=\{0:F\}}"/>
<Button Content="Russian" Click="OnCultureClick" CommandParameter="RU" Margin="10"/>
<Button Content="English-USA" Click="OnCultureClick" CommandParameter="En-Us" Margin="10"/>
</UniformGrid>
<x:Code><![CDATA[
private void OnCultureClick(object sender, RoutedEventArgs e)
{
string lang = ((Button)sender).CommandParameter as string;
if (lang == null)
LanguageAware.SetCurrentLanguage(null);
else
LanguageAware.SetCurrentLanguage(XmlLanguage.GetLanguage(lang));
}]]>
</x:Code>
用命令替换 XAML 中的答题器的标记扩展:
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Threading;
namespace Wpf.Data
{
[MarkupExtensionReturnType(typeof(ICommand))]
public class LanguageCommandExtension : MarkupExtension
{
private static readonly LanguageCommand command = new LanguageCommand();
public void RaiseCanExecuteChanged() => command.RaiseCanExecuteChanged();
public override object ProvideValue(IServiceProvider serviceProvider)
{
return command;
}
private class LanguageCommand : ICommand
{
private readonly EventHandler requerySuggested;
/// <inheritdoc cref="ICommand.CanExecuteChanged"/>
public event EventHandler CanExecuteChanged;
private static readonly Dispatcher dispatcher = Application.Current.Dispatcher;
/// <summary> The method that raises the event <see cref="CanExecuteChanged"/>.</summary>
public void RaiseCanExecuteChanged()
{
if (dispatcher.CheckAccess())
{
invalidate();
}
else
{
_ = dispatcher.BeginInvoke(invalidate);
}
}
private readonly Action invalidate;
public LanguageCommand()
{
invalidate = () => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
requerySuggested = (o, e) => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
CommandManager.RequerySuggested += requerySuggested;
}
/// <inheritdoc cref="ICommand.CanExecute(object)"/>
public bool CanExecute(object parameter)
{
if (parameter == null || parameter is XmlLanguage)
{
return true;
}
try
{
if (parameter is string str)
{
return XmlLanguage.GetLanguage(str) != null;
}
if (parameter is CultureInfo culture)
{
str = culture.Name;
return XmlLanguage.GetLanguage(str) != null;
}
}
catch (Exception)
{ }
return false;
}
/// <inheritdoc cref="ICommand.Execute(object)"/>
public void Execute(object parameter)
{
if (parameter is XmlLanguage language)
{ }
else if (parameter == null)
{
language = null;
}
else
{
try
{
if (parameter is string str)
{
language = XmlLanguage.GetLanguage(str);
}
else if (parameter is CultureInfo culture)
{
str = culture.Name;
language = XmlLanguage.GetLanguage(str);
}
else
{
throw new InvalidCastException(nameof(parameter));
}
}
catch (Exception)
{
throw new ArgumentException(nameof(parameter));
}
}
LanguageAware.SetCurrentLanguage(language);
}
}
}
}
设置面板语言的示例:
<Window.Resources>
<sys:DateTime x:Key="date">12.31.2021 15:47</sys:DateTime>
</Window.Resources>
<UniformGrid Columns="1"
Language="{Binding Path=(wpfdata:LanguageAware.CurrentLanguage)}">
<TextBlock Text="{Binding Path=(wpfdata:LanguageAware.CurrentLanguage)}" />
<TextBox Text="{Binding Mode=OneWay, Source={StaticResource date}, StringFormat=\{0:F\}}"/>
<TextBox Text="{Binding Mode=OneWay, Source={StaticResource date}, StringFormat=\{0:F\}}"/>
<Button Content="Russian" Command="{wpfdata:LanguageCommand}" CommandParameter="RU" Margin="10"/>
<Button Content="English-USA" Command="{wpfdata:LanguageCommand}" CommandParameter="En-Us" Margin="10"/>
</UniformGrid>
语言的标记扩展 属性:
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
namespace Wpf.Data
{
[MarkupExtensionReturnType(typeof(Binding))]
public class LanguageAwareExtension : Binding
{
public LanguageAwareExtension()
{
Path = new PropertyPath(
"(0)",
typeof(LanguageAware).GetProperty(nameof(LanguageAware.CurrentLanguage)));
ConverterCulture = CultureInfo.CurrentCulture;
}
}
}
设置Window语言的示例:
<Window ----------------------------
----------------------------
Language="{wpfdata:LanguageAware}">
<Window.Resources>
<sys:DateTime x:Key="date">12.31.2021 15:47</sys:DateTime>
</Window.Resources>
<UniformGrid Columns="1">
<TextBlock Text="{Binding Path=(wpfdata:LanguageAware.CurrentLanguage)}" />
<TextBox Text="{Binding Mode=OneWay, Source={StaticResource date}, StringFormat=\{0:F\}}"/>
<TextBox Text="{Binding Mode=OneWay, Source={StaticResource date}, StringFormat=\{0:F\}}"/>
<Button Content="Russian" Command="{wpfdata:LanguageCommand}" CommandParameter="RU" Margin="10"/>
<Button Content="English-USA" Command="{wpfdata:LanguageCommand}" CommandParameter="En-Us" Margin="10"/>
</UniformGrid>
</Window>
答案
App.xaml.cs
public App()
{
CultureInfo CultureInformation = new CultureInfo("en-US");
CultureInformation.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
CultureInformation.DateTimeFormat.LongDatePattern = "ddd, dd/MM/yyyy";
CultureInfo.DefaultThreadCurrentCulture = CultureInformation;
CultureInfo.DefaultThreadCurrentUICulture = CultureInformation;
//
XmlLanguage language = XmlLanguage.GetLanguage(CultureInformation.IetfLanguageTag);
const BindingFlags kField = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
typeof(XmlLanguage).GetField("_equivalentCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_compatibleCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_specificCulture", kField).SetValue(language, CultureInformation);
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(language));
}
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;
//
XmlLanguage language = XmlLanguage.GetLanguage(CultureInformation.IetfLanguageTag);
const BindingFlags kField = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
typeof(XmlLanguage).GetField("_equivalentCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_compatibleCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_specificCulture", kField).SetValue(language, CultureInformation);
this.Language = language;
}
else if (Language == "English")
{
CultureInfo CultureInformation = CultureInfo.CreateSpecificCulture("en-US");
CultureInformation.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
CultureInformation.DateTimeFormat.LongDatePattern = "ddd, dd/MM/yyyy";
Thread.CurrentThread.CurrentCulture = CultureInformation;
Thread.CurrentThread.CurrentUICulture = CultureInformation;
//
XmlLanguage language = XmlLanguage.GetLanguage(CultureInformation.IetfLanguageTag);
const BindingFlags kField = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
typeof(XmlLanguage).GetField("_equivalentCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_compatibleCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_specificCulture", kField).SetValue(language, CultureInformation);
this.Language = language;
}
}
有没有 ConverterCulture class
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="{Binding Path=StartTime, StringFormat={}{0:hh:mm tt}}"/>
<TextBlock Text="" FontSize="12" FontFamily="{StaticResource Segoe Icons}"/>
<TextBlock Text="{Binding Path=EndTime, StringFormat={}{0:hh:mm tt}}"/>
</TextBlock>