| File: MarkupExtensions\OnIdiomExtension.cs | Web Access |
| Project: src\src\Controls\src\Xaml\Controls.Xaml.csproj (Microsoft.Maui.Controls.Xaml) |
using System; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Reflection; using System.Xml; using Microsoft.Extensions.DependencyInjection; using Microsoft.Maui.Devices; namespace Microsoft.Maui.Controls.Xaml { [ContentProperty(nameof(Default))] [RequireService( [typeof(IProvideValueTarget), typeof(IValueConverterProvider), typeof(IXmlLineInfoProvider), typeof(IConverterOptions)])] [RequiresUnreferencedCode("The OnIdiomExtension is not trim safe. Use OnIdiom<T> instead.")] public class OnIdiomExtension : IMarkupExtension { // See Device.Idiom public object Default { get; set; } public object Phone { get; set; } public object Tablet { get; set; } public object Desktop { get; set; } public object TV { get; set; } public object Watch { get; set; } public IValueConverter Converter { get; set; } public object ConverterParameter { get; set; } public object ProvideValue(IServiceProvider serviceProvider) { if (Default == null && Phone == null && Tablet == null && Desktop == null && TV == null && Watch == null) throw new XamlParseException("OnIdiomExtension requires a non-null value to be specified for at least one idiom 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 value = GetValue(); if (value == null && propertyType.IsValueType) return Activator.CreateInstance(propertyType); if (Converter != null) return Converter.Convert(value, propertyType, ConverterParameter, CultureInfo.CurrentUICulture); var converterProvider = serviceProvider?.GetService<IValueConverterProvider>(); if (converterProvider != null) { 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); } } return converterProvider.Convert(value, propertyType, minforetriever, serviceProvider); } if (converterProvider != null) return converterProvider.Convert(value, propertyType, () => pi, serviceProvider); var ret = value.ConvertTo(propertyType, () => pi, serviceProvider, out Exception exception); if (exception != null) throw exception; return ret; } object GetValue() { if (DeviceInfo.Idiom == DeviceIdiom.Phone) return Phone ?? Default; if (DeviceInfo.Idiom == DeviceIdiom.Tablet) return Tablet ?? Default; if (DeviceInfo.Idiom == DeviceIdiom.Desktop) return Desktop ?? Default; if (DeviceInfo.Idiom == DeviceIdiom.TV) return TV ?? Default; if (DeviceInfo.Idiom == DeviceIdiom.Watch) return Watch ?? Default; return Default; } } }