| File: MarkupExtensions\AppThemeBindingExtension.cs | Web Access |
| Project: src\src\Controls\src\Xaml\Controls.Xaml.csproj (Microsoft.Maui.Controls.Xaml) |
using System; using System.Globalization; using System.Reflection; using Microsoft.Extensions.DependencyInjection; namespace Microsoft.Maui.Controls.Xaml { [ContentProperty(nameof(Default))] [RequireService( [typeof(IProvideValueTarget), typeof(IValueConverterProvider), typeof(IXmlLineInfoProvider), typeof(IConverterOptions)])] public class AppThemeBindingExtension : IMarkupExtension<BindingBase> { object _default; bool _hasdefault; object _light; bool _haslight; object _dark; bool _hasdark; public object Default { get => _default; set { _default = value; _hasdefault = true; } } public object Light { get => _light; set { _light = value; _haslight = true; } } public object Dark { get => _dark; set { _dark = value; _hasdark = true; } } public object Value { get; private set; } public object ProvideValue(IServiceProvider serviceProvider) => (this as IMarkupExtension<BindingBase>).ProvideValue(serviceProvider); BindingBase IMarkupExtension<BindingBase>.ProvideValue(IServiceProvider serviceProvider) { if (Default == null && Light == null && Dark == null) throw new XamlParseException("AppThemeBindingExtension requires a non-null value to be specified for at least one theme or Default.", serviceProvider); var valueProvider = serviceProvider?.GetService<IProvideValueTarget>() ?? throw new ArgumentException(); BindableProperty bp; PropertyInfo pi = null; Type propertyType = null; if (valueProvider.TargetObject is Setter setter) bp = setter.Property; else { bp = valueProvider.TargetProperty as BindableProperty; pi = valueProvider.TargetProperty as PropertyInfo; } propertyType = bp?.ReturnType ?? pi?.PropertyType ?? throw new InvalidOperationException("Cannot determine property to provide the value for."); var converterProvider = serviceProvider?.GetService<IValueConverterProvider>(); MemberInfo minforetriever() { if (pi != null) return pi; MemberInfo minfo = null; try { minfo = bp.DeclaringType.GetRuntimeProperty(bp.PropertyName); } catch (AmbiguousMatchException e) { throw new XamlParseException($"Multiple properties with name '{bp.DeclaringType}.{bp.PropertyName}' found.", serviceProvider, innerException: e); } if (minfo != null) return minfo; try { return bp.DeclaringType.GetRuntimeMethod("Get" + bp.PropertyName, new[] { typeof(BindableObject) }); } catch (AmbiguousMatchException e) { throw new XamlParseException($"Multiple methods with name '{bp.DeclaringType}.Get{bp.PropertyName}' found.", serviceProvider, innerException: e); } } var binding = new AppThemeBinding(); if (converterProvider != null) { if (_haslight) binding.Light = converterProvider.Convert(Light, propertyType, minforetriever, serviceProvider); if (_hasdark) binding.Dark = converterProvider.Convert(Dark, propertyType, minforetriever, serviceProvider); if (_hasdefault) binding.Default = converterProvider.Convert(Default, propertyType, minforetriever, serviceProvider); return binding; } Exception converterException = null; if (converterException != null && _haslight) binding.Light = Light.ConvertTo(propertyType, minforetriever, serviceProvider, out converterException); if (converterException != null && _hasdark) binding.Dark = Dark.ConvertTo(propertyType, minforetriever, serviceProvider, out converterException); if (converterException != null && _hasdefault) binding.Default = Default.ConvertTo(propertyType, minforetriever, serviceProvider, out converterException); if (converterException != null) throw converterException; return binding; } } }