CommunityToolkit/Maui.Markup

[Proposal] Add `.Text()` and `.TextColor()` Extension Methods

brminnick opened this issue · 4 comments

Add .Text() + .TextColor() Extension Methods

  • Proposed
  • Prototype
  • Implementation
    • iOS Support
    • Android Support
    • macOS Support
    • Windows Support
  • Unit Tests
  • Sample
  • Documentation

Link to Discussion

#37

Summary

This Proposal adds extension methods for IText.Text and ITextStyle.TextColor.

Motivation

Currently, the only way to set Text and TextColor properties on an element that implements IText is to set the properties directly. Here is an example from CommunityToolkit.Maui.Markup.Sample.Pages.SettingsPage:

new Label { Text = "Top Stories To Fetch", TextColor = ColorConstants.PrimaryTextColor }
	.LayoutFlags(AbsoluteLayoutFlags.XProportional | AbsoluteLayoutFlags.WidthProportional)
	.LayoutBounds(0, 0, 1, 40)
	.TextCenterHorizontal()
	.TextBottom(),

This Proposal will allow devs to use fluent extension methods to set both Text and TextColor.

Detailed Design

	/// <summary>
	/// Sets <see cref="ITextStyle.TextColor"/> Property
	/// </summary>
	/// <typeparam name="TBindable"><see cref="BindableObject"/></typeparam>
	/// <param name="bindable">Element</param>
	/// <param name="textColor">Text <see cref="Color"/></param>
	/// <returns></returns>
	public static TBindable TextColor<TBindable>(this TBindable bindable, Color? textColor) where TBindable : BindableObject, ITextStyle
	{
		bindable.SetValue(TextElement.TextColorProperty, textColor);
		return bindable;
	}

	/// <summary>
	/// Sets <see cref="IText.Text"/> Property
	/// </summary>
	/// <typeparam name="TBindable"><see cref="BindableObject"/></typeparam>
	/// <param name="bindable">Element</param>
	/// <param name="text"></param>
	/// <returns></returns>
	public static TBindable Text<TBindable>(this TBindable bindable, string? text) where TBindable : BindableObject, IText
	{
		bindable.SetValue(ITextElement.TextProperty, text);
		return bindable;
	}

	/// <summary>
	/// Sets <see cref="IText.Text"/> Property
	/// </summary>
	/// <typeparam name="TBindable"><see cref="BindableObject"/></typeparam>
	/// <param name="bindable">Element</param>
	/// <param name="text"></param>
	/// <param name="textColor">Text <see cref="Color"/></param>
	public static TBindable Text<TBindable>(this TBindable bindable, string? text, Color? textColor) where TBindable : BindableObject, IText
	{
		return bindable.Text(text).TextColor(textColor);
	}

Usage Syntax

C# Usage

Content = new VerticalStackLayout
{
  Children = 
  {
    new Label()
      .Text("Hello World", Colors.Blue),

    new Label()
      .TextColor(Colors.Green)
      .Bind(Label.TextProperty, nameof(ViewModel.LabelText);
  }
}

Drawbacks

Currently, TextElement does not have a TextProperty static property, i.e. TextElelement.TextProperty does not yet exist.

We can workaround this by doing the following. This is a proven and common workaround in Xamarin.CommunityToolkit.Markup.

using ITextElement = Microsoft.Maui.Controls.Label; // ToDo Remove this once TextElement.TextProperty is added

public static class ElementExtensions
{
	public static TBindable Text<TBindable>(this TBindable bindable, string? text) where TBindable : BindableObject, IText
	{
		bindable.SetValue(ITextElement.TextProperty, text);
		return bindable;
	}
}

Alternatives

Currently, the only alternative is to initialize the properties like so:

new Label { Text = "Top Stories To Fetch", TextColor = ColorConstants.PrimaryTextColor }

Unresolved Questions

Should we support null inputs? The default value of Color and Text is null and I imagine the number of use cases where developer would use this .Text() to revert the values of Color and Text back to null may be minimal.

gets my vote!

I vote to approve it!

I vote to approve ✅

Reopening Proposal.

Only Proposals moved to the Closed Project Column and Completed Project Column can be closed.