using System; using System.Windows; using System.Windows.Data; using System.Windows.Markup; using HandyControl.Properties.Langs; namespace HandyControl.Tools.Extension; public class LangExtension : MarkupExtension { private readonly DependencyObject _proxy; public LangExtension() { _proxy = new DependencyObject(); Source = LangProvider.Instance; } public LangExtension(string key) : this() { Key = key; } public static readonly DependencyProperty KeyProperty = DependencyProperty.RegisterAttached( "Key", typeof(object), typeof(LangExtension), new PropertyMetadata(default)); public object Key { get => _proxy.GetValue(KeyProperty); set => _proxy.SetValue(KeyProperty, value); } private static readonly DependencyProperty TargetPropertyProperty = DependencyProperty.RegisterAttached( "TargetProperty", typeof(DependencyProperty), typeof(LangExtension), new PropertyMetadata(default(DependencyProperty))); private static void SetTargetProperty(DependencyObject element, DependencyProperty value) => element.SetValue(TargetPropertyProperty, value); private static DependencyProperty GetTargetProperty(DependencyObject element) => (DependencyProperty) element.GetValue(TargetPropertyProperty); public BindingMode Mode { get; set; } public IValueConverter Converter { get; set; } public object ConverterParameter { get; set; } public object Source { 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; switch (Key) { case string key: { var binding = CreateLangBinding(key); BindingOperations.SetBinding(targetObject, targetProperty, binding); return binding.ProvideValue(serviceProvider); } case Binding keyBinding when targetObject is FrameworkElement element: { if (element.DataContext != null) { var binding = SetLangBinding(element, targetProperty, keyBinding.Path, element.DataContext); return binding.ProvideValue(serviceProvider); } SetTargetProperty(element, targetProperty); element.DataContextChanged += LangExtension_DataContextChanged; break; } case Binding keyBinding when targetObject is FrameworkContentElement element: { if (element.DataContext != null) { var binding = SetLangBinding(element, targetProperty, keyBinding.Path, element.DataContext); return binding.ProvideValue(serviceProvider); } SetTargetProperty(element, targetProperty); element.DataContextChanged += LangExtension_DataContextChanged; break; } } return string.Empty; } private void LangExtension_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e) { switch (sender) { case FrameworkElement element: { element.DataContextChanged -= LangExtension_DataContextChanged; if (!(Key is Binding keyBinding)) return; var targetProperty = GetTargetProperty(element); SetTargetProperty(element, null); SetLangBinding(element, targetProperty, keyBinding.Path, element.DataContext); break; } case FrameworkContentElement element: { element.DataContextChanged -= LangExtension_DataContextChanged; if (!(Key is Binding keyBinding)) return; var targetProperty = GetTargetProperty(element); SetTargetProperty(element, null); SetLangBinding(element, targetProperty, keyBinding.Path, element.DataContext); break; } } } private BindingBase SetLangBinding(DependencyObject targetObject, DependencyProperty targetProperty, PropertyPath path, object dataContext) { if (targetProperty == null) return null; BindingOperations.SetBinding(targetObject, targetProperty, new Binding { Path = path, Source = dataContext, Mode = BindingMode.OneWay }); var key = targetObject.GetValue(targetProperty) as string; if (string.IsNullOrEmpty(key)) return null; var binding = CreateLangBinding(key); BindingOperations.SetBinding(targetObject, targetProperty, binding); return binding; } private BindingBase CreateLangBinding(string key) => new Binding(key) { Converter = Converter, ConverterParameter = ConverterParameter, UpdateSourceTrigger = UpdateSourceTrigger.Explicit, Source = Source, Mode = BindingMode.OneWay }; }