XAML使用扩展标记完成无重启刷新多语言功能

B站影视 电影资讯 2025-09-27 08:39 1

摘要:随着现代化程序的多样性,很多程序都走向了国际化,在这种国家化的背景下,自然需要多种语言的适配兼容。但是以往的多语言切换都是需要软件重启才能解决,现在很多24小时自助终端,是不能进行重启的,那么这个重启更新多语言显得效果是致命的,我们得解决不能重启就能实现多语言

多语言需求背景

随着现代化程序的多样性,很多程序都走向了国际化,在这种国家化的背景下,自然需要多种语言的适配兼容。但是以往的多语言切换都是需要软件重启才能解决,现在很多24小时自助终端,是不能进行重启的,那么这个重启更新多语言显得效果是致命的,我们得解决不能重启就能实现多语言切换的功能。

实现多语言切换的条件

翻译源(这里的翻译源就是你的他国语言的翻译数据存储的地方,这里可以是数据库、XAML文件、CSV等等多样文件,本章节就以XAML稳准进行讲解实现)

MarkupExtension定制

多值转换器(MultiValueConverter)

绑定(Binding)

依赖属性

业务使用 场景

静态翻译(直接参与数据源查找显示)

动态翻译(直接进行绑定翻译,如Text="{local:Language {Binding UsreName}}")

重要翻译解析逻辑

继承MarkupExtension扩展支持绑定翻译

通过Binding的内容进行解析出值,结合字典进行Key,Value获取,例如 Binding UsreName的值是 "欢迎使用WPF",字典中的键值对为 Welcome to WPF

创建不同国家的翻译字典,字典中存储不同国家的翻译语言

利用代码绑定方式,通过多值转换器将Binding和字典进行捆绑起来,当Binding中的值或者字典发生变化即可触发转换器,直接进行只转换

示例代码

/// /// 语言扩展 /// public class LanguageExtension : MarkupExtension { private readonly DependencyObject _proxy; public static readonly DependencyProperty KeyProperty = DependencyProperty.RegisterAttached( "Key", typeof(object), typeof(LanguageExtension), new PropertyMetadata(default)); /// /// 需要翻译的数据 /// public object Key { get => _proxy.GetValue(KeyProperty); set => _proxy.SetValue(KeyProperty, value); } public LanguageExtension { _proxy = new DependencyObject; } public LanguageExtension(object key) : this { Key = key; } /// /// 设计模式显示内容 /// public object DesignValue { get; set; } public override object ProvideValue(IServiceProvider serviceProvider) { if (!(serviceProvider.GetService(typeof(IProvideValueTarget)) is IProvideValueTarget provideValueTarget)) return this; if (provideValueTarget.TargetObject.GetType.FullName == "System.Windows.SharedDp") return this; if (!(provideValueTarget.TargetObject is DependencyObject targetObject)) return this; if (!(provideValueTarget.TargetProperty is DependencyProperty targetProperty)) return this; if (DesignerProperties.GetIsInDesignMode(targetObject)) return DesignValue; RoutedEventHandler Unload = null; RoutedEventHandler Loaded = null; EventHandler ChangedHandler = null; DependencyPropertyChangedEventHandler changedEventHandler = null; ChangedHandler = (o, e) => targetObject.Dispatcher.BeginInvoke(new Action( => BindingOperations.SetBinding(targetObject, targetProperty, CreateBinding(Key)))); LanguageService.ChangedEvent += ChangedHandler; Unload = (o, e) => { if (o is FrameworkElement frameworkElement) frameworkElement.Unloaded -= Unload; if (o is FrameworkContentElement contentElement) contentElement.Unloaded -= Unload; LanguageService.ChangedEvent -= ChangedHandler; }; Loaded = (o, e) => { if (o is FrameworkElement frameworkElement) frameworkElement.Loaded -= Loaded; if (o is FrameworkContentElement contentElement) contentElement.Loaded -= Loaded; targetObject.Dispatcher.BeginInvoke(new Action( => BindingOperations.SetBinding(targetObject, targetProperty, CreateBinding(Key)))); }; switch (Key) { case Binding keyBinding when targetObject is FrameworkElement element: { if (element.DataContext != null) { return CreateBinding(Key).ProvideValue(serviceProvider); } changedEventHandler = (sender, e) => { element.DataContextChanged -= changedEventHandler; if (!(Key is Binding)) return; SetLangBinding(element, targetProperty, keyBinding.Path, element.DataContext); }; element.Loaded += Loaded; element.Unloaded += Unload; element.DataContextChanged += changedEventHandler; } break; case Binding keyBinding when targetObject is FrameworkContentElement element: { { } { }; } break; default: var binding = CreateBinding(Key); BindingOperations.SetBinding(targetObject, targetProperty, binding); return binding.ProvideValue(serviceProvider); } return string.Empty; } private void SetLangBinding(DependencyObject element, DependencyProperty property, PropertyPath path, object dataContext) { if (property == null) return; BindingOperations.SetBinding(element, property, new Binding { Path = path, Source = dataContext, Mode = BindingMode.OneWay }); var key = element.GetValue(property) as string; if (string.IsNullOrEmpty(key)) return; BindingOperations.SetBinding(element, property, CreateBinding(key)); } /// /// 创建绑定 /// /// /// private BindingBase CreateBinding(object content) { MultiBinding languageBinding = new MultiBinding; var path = string.Empty; if (content is Binding binding) { if (binding.Path != null) path = binding.Path.Path; languageBinding.Bindings.Add(binding); } if (content is string key) { path = key; languageBinding.Bindings.Add(new Binding { Source = path, Mode = BindingMode.OneWay, }); } { Source = new ResourceDictionary,//当前字典即为多语言翻译字典源文件 }); languageBinding.ConverterParameter = DesignValue; languageBinding.Converter = new LanguageConverter; return languageBinding; } } internal class LanguageConverter : IMultiValueConverter { public object Convert(object values, Type targetType, object parameter, CultureInfo culture) { if (values.Length != 2 || values[0] is null || !(values[1] is ResourceDictionary languages)) return parameter; if (values[0].Equals(DependencyProperty.UnsetValue)) return parameter; var key = values[0].ToString; var value = languages.Contains(key) ? languages[key] : key; return value; } public object ConvertBack(object value, Type targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException; } }

注意

当前多语言翻译功能同时适用Avalonia等其他XAML相关的开发框架

来源:opendotnet

相关推荐