MAUI:自定义条目

MAUI : Customize an Entry

我是 MAUI 新手,对 Xamarin.Forms

有基本了解

我想在 MAUI 中为 Entry 控件添加底部边框(和边框刻度)。

在 Xamarin.Forms,我们必须创建一个自定义控件,然后为每个平台创建一个渲染器。

在发布此消息之前,我在互联网上进行了研究。它涉及处理程序,我的印象是它只允许进行基本修改(更改背景颜色等)。

我对所有这些信息有点困惑,如果有人能启发我,我将不胜感激。

Customize specific control instances 显示了一个自定义条目的简单示例,它仅针对每个平台自定义一些属性。

我已经开始创建 .Net Maui advanced custom Entry example。到目前为止,请参阅该回购协议。

状态:

  • 演示 Windows 上的下划线颜色和粗细。
  • 在 Android 上有下划线的开头。

限制(当前):

  • 在 Windows 上,一些 Entry properties 需要映射到包含的文本框。
  • 尚未测试 Entry events,看看是否需要任何特殊处理。
  • Android 下划线无法控制其粗细或颜色。
  • 除了 Windows 或 iOS 以外的平台没有实现。

如果你想进一步扩展,google xamarin forms customize entry renderer platform-specific 代码示例。希望我已经展示了足够多的内容来让大家了解 how/where 添加这样的代码。


在这个时候,做一个高级示例似乎比相应的 Xamarin Forms“自定义渲染器”工作更多。

原因:

  • 需要适应 Maui 的处理程序映射方案。可能只需要高级文档和示例。
  • 由于 IEntryIEntryHandler 需要的类型,难以扩展现有的 EntryHandler。如何覆盖 PlatformView 的类型??
  • 难以复制现有处理程序的功能(以便进行细微更改),因为 built-in 处理程序使用的某些扩展是“内部的”,因此必须复制这些文件。其中提到了其他文件。然后我复制了。并进行了一些更改以避免与现有扩展的歧义冲突。

待定:也许有办法避免我遇到的并发症。
另外可能有我复制的代码,可以省略。


这些是需要完成的步骤:

  1. 使用所需的附加属性定义 class MyEntry : Entry
  2. 定义 class MyEntryHandler 以呈现原生 UI 个对象。
  3. MauiProgram 中的添加处理程序。

1.使用所需的附加属性定义 class MyEntry : Entry

在这里,我们添加UnderlineColorUnderlineThickness

public class MyEntry : Entry
{
    /// <summary>
    /// Color and Thickness of bottom border.
    /// </summary>
    public static BindableProperty UnderlineColorProperty = BindableProperty.Create(
            nameof(UnderlineColor), typeof(Color), typeof(MyEntry), Colors.Black);
    public Color UnderlineColor
    {
        get => (Color)GetValue(UnderlineColorProperty);
        set => SetValue(UnderlineColorProperty, value);
    }

    public static BindableProperty UnderlineThicknessProperty = BindableProperty.Create(
            nameof(UnderlineThickness), typeof(int), typeof(MyEntry), 0);
    public int UnderlineThickness
    {
        get => (int)GetValue(UnderlineThicknessProperty);
        set => SetValue(UnderlineThicknessProperty, value);
    }

    public MyEntry()
    {
    }
}

2。定义 class MyEntryHandler 以呈现为本机 UI 对象。

这是用 partial class 完成的。一个部分是 cross-platform,然后需要为您实现的每个平台使用另一部分。

在我的存储库中,找到 MyEntryHandler.csWindows/MyEntryHandler.Windows.csAndroid/MyEntryHandler.Android.cs

MyEntryHandler.cs:

这包含 MyEntryHandler 的“映射器”。

    // Cross-platform partial of class. See Maui repo maui\src\Core\src\Handlers\Entry\EntryHandler.cs
    public partial class MyEntryHandler : IMyEntryHandler //: EntryHandler
    {
        // static c'tor.
        static MyEntryHandler()
        {
            // TBD: Fill MyMapper here by copying from Entry.Mapper, then add custom ones defined in MyEntry?
        }

        //public static IPropertyMapper<IEntry, IEntryHandler> MyMapper => Mapper;
        public static IPropertyMapper<IEntry, MyEntryHandler> MyMapper = new PropertyMapper<IEntry, MyEntryHandler>(ViewMapper)
        {
            // From Entry.
            [nameof(IEntry.Background)] = MapBackground,
            [nameof(IEntry.CharacterSpacing)] = MapCharacterSpacing,
            [nameof(IEntry.ClearButtonVisibility)] = MapClearButtonVisibility,
            [nameof(IEntry.Font)] = MapFont,
            [nameof(IEntry.IsPassword)] = MapIsPassword,
            [nameof(IEntry.HorizontalTextAlignment)] = MapHorizontalTextAlignment,
            [nameof(IEntry.VerticalTextAlignment)] = MapVerticalTextAlignment,
            [nameof(IEntry.IsReadOnly)] = MapIsReadOnly,
            [nameof(IEntry.IsTextPredictionEnabled)] = MapIsTextPredictionEnabled,
            [nameof(IEntry.Keyboard)] = MapKeyboard,
            [nameof(IEntry.MaxLength)] = MapMaxLength,
            [nameof(IEntry.Placeholder)] = MapPlaceholder,
            [nameof(IEntry.PlaceholderColor)] = MapPlaceholderColor,
            [nameof(IEntry.ReturnType)] = MapReturnType,
            [nameof(IEntry.Text)] = MapText,
            [nameof(IEntry.TextColor)] = MapTextColor,
            [nameof(IEntry.CursorPosition)] = MapCursorPosition,
            [nameof(IEntry.SelectionLength)] = MapSelectionLength,
            // From MyEntry
            [nameof(MyEntry.UnderlineThickness)] = MapUnderlineThickness
        };

        // TBD: What is this for? Cloned one on Entry.
        private static void MapUnderlineThickness(MyEntryHandler arg1, IEntry arg2)
        {
        }


        public MyEntryHandler() : base(MyMapper)
        {
        }

我还没有在所有平台文件夹中创建最小部分 classes。在 repo 的 cross-platform MyEntryHandler 中,您会在 #if WINDOWS 中看到代码。目的是不需要将其包装在 #if 中。您还会看到很多注释掉的代码;这样我就可以看到需要在每个平台上实现哪些方法。

MyEntryHandler.Windows.cs:

本质是CreatePlatformView()。在 Windows 上,我选择实现为包含 TextBox.

Border(除底部外所有边均为零)
        protected override PlatformView CreatePlatformView()
        {
            var myentry = VirtualView as MyEntry;

            var textbox = new MauiPasswordTextBox
            {
                // From EntryHandler.
                IsObfuscationDelayed = s_shouldBeDelayed

                // TODO: pass some entry properties through to textbox?
            };

            MauiColor color = myentry != null
                    ? myentry.UnderlineColor
                    : MyEntry.UnderlineColorProperty.DefaultValue as MauiColor;
            int thickness = myentry != null
                    ? myentry.UnderlineThickness
                    : (int)MyEntry.UnderlineThicknessProperty.DefaultValue;

            var border = new Border
            {
                Child = textbox,
                BorderBrush = color.ToPlatform(),
                BorderThickness = new Thickness(0, 0, 0, thickness)
            };


            return border;
        }

Windows 处理程序还有许多其他行。这些都是从毛伊岛源复制过来的。需要哪些(如果有的话)待定。如果我想出如何简单地从 Maui 的 EntryHandler 继承,就不需要这些了。但是继承的时候有type冲突


3: MauiProgram中的AddHandler.

MauiProgram.cs

    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureMauiHandlers(handlers =>
            {
                handlers.AddHandler(typeof(MyEntry), typeof(MyEntryHandler));
            })
        ...

您会在存储库中看到其他 classes 添加到 Maui 项目。这些是从毛伊岛来源复制的。

这些其他 classes 被上面提到的 classes 引用。

希望其他大多数 class 消失,一旦这个主题得到更好的理解。


在 Windows 上,AppShell + MainPage 有两个 MyEntry。一个是带下划线和彩色的。

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:myviews="clr-namespace:MauiCustomEntryHandler"
             x:Class="MauiCustomEntryHandler.MainPage">
             
    <ScrollView>
        <VerticalStackLayout 
                WidthRequest="500" HeightRequest="400"
                Spacing="25" Padding="30,0" BackgroundColor="LightBlue"
                HorizontalOptions="Center" VerticalOptions="Center">
            <Label Text="Hello, Maui!" FontSize="24" HorizontalOptions="Center" />
            <myviews:MyEntry Text="test" FontSize="20" UnderlineThickness="8"
                 UnderlineColor="Purple" BackgroundColor="HotPink" />
            <myviews:MyEntry UnderlineThickness="0" BackgroundColor="LightGray" />
        </VerticalStackLayout>
    </ScrollView>
 
</ContentPage>