File: ContentConverter.cs
Web Access
Project: src\src\Controls\src\Core\Controls.Core.csproj (Microsoft.Maui.Controls)
#nullable disable
using System;
using System.Globalization;
using Microsoft.Maui.Controls.Internals;
 
namespace Microsoft.Maui.Controls
{
	internal class ContentConverter : IValueConverter
	{
		public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
		{
			var presenter = parameter as ContentPresenter;
 
			if (value is View view)
			{
				return ConfigureView(view, presenter);
			}
 
			if (value is string textContent)
			{
				return ConvertToLabel(textContent, presenter);
			}
 
			return value;
		}
 
		public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
		{
			throw new NotImplementedException();
		}
 
		static View ConfigureView(View view, ContentPresenter presenter)
		{
			if (view is ITextElement && HasTemplateAncestor(presenter, typeof(ITextElement)))
			{
				BindTextProperties(view);
			}
 
			if (view is IFontElement && HasTemplateAncestor(presenter, typeof(IFontElement)))
			{
				BindFontProperties(view);
			}
 
			return view;
		}
 
		static Label ConvertToLabel(string textContent, ContentPresenter presenter)
		{
			var label = new Label
			{
				Text = textContent
			};
 
			if (HasTemplateAncestor(presenter, typeof(ITextElement)))
			{
				BindTextProperties(label);
			}
 
			if (HasTemplateAncestor(presenter, typeof(IFontElement)))
			{
				BindFontProperties(label);
			}
 
			return label;
		}
 
		static void BindTextProperties(BindableObject content)
		{
			var source = new RelativeBindingSource(RelativeBindingSourceMode.FindAncestor, typeof(ITextElement));
			if (ShouldSetBinding(content, TextElement.TextColorProperty))
			{
				content.SetBinding(TextElement.TextColorProperty, static (ITextElement te) => te.TextColor, source: source);
			}
 
			if (ShouldSetBinding(content, TextElement.CharacterSpacingProperty))
			{
				content.SetBinding(TextElement.CharacterSpacingProperty, static (ITextElement te) => te.CharacterSpacing, source: source);
			}
 
			if (ShouldSetBinding(content, TextElement.TextTransformProperty))
			{
				content.SetBinding(TextElement.TextTransformProperty, static (ITextElement te) => te.TextTransform, source: source);
			}
		}
 
		static void BindFontProperties(BindableObject content)
		{
			var source = new RelativeBindingSource(RelativeBindingSourceMode.FindAncestor, typeof(IFontElement));
			if (ShouldSetBinding(content, FontElement.FontAttributesProperty))
			{
				content.SetBinding(FontElement.FontAttributesProperty, static (IFontElement fe) => fe.FontAttributes, source: source);
			}
 
			if (ShouldSetBinding(content, FontElement.FontSizeProperty))
			{
				content.SetBinding(FontElement.FontSizeProperty, static (IFontElement fe) => fe.FontSize, source: source);
			}
 
			if (ShouldSetBinding(content, FontElement.FontFamilyProperty))
			{
				content.SetBinding(FontElement.FontFamilyProperty, static (IFontElement fe) => fe.FontFamily, source: source);
			}
		}
 
		static bool ShouldSetBinding(BindableObject content, BindableProperty property)
		{
			return !content.IsSet(property) && !content.GetIsBound(property);
		}
 
		static bool HasTemplateAncestor(ContentPresenter presenter, Type type)
		{
			var parent = presenter?.Parent;
 
			while (parent != null)
			{
				if (type.IsAssignableFrom(parent.GetType()))
				{
					return true;
				}
 
				if (parent is ContentView)
				{
					break;
				}
 
				parent = parent.Parent;
			}
 
			return false;
		}
	}
}