在 .NET MAUI 中如何更好地自定义控件

这篇具有很好参考价值的文章主要介绍了在 .NET MAUI 中如何更好地自定义控件。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

今天,我想谈谈并向您展示在.NET MAUI中完全自定义控件的方法。在查看.NET MAUI之前,让我们回到几年前,回到 Xamarin.Forms 时代。那时,我们有很多自定义控件的方法, 比如当您不需要访问平台特有的 API 来自定义控件时,可以使用Behaviors;如果您需要访问平台特有的 API,可以使用 Effects。

让我们稍微关注一下Effects API。它是由于 Xamarin 缺乏多目标体系结构而创建的。这意味着我们无法在共享级别(在 .NET 标准 csproj 中)访问特定于平台的代码。它工作得很好,可以让您免于创建自定义渲染器。

今天,在 .NET MAUI 中,我们可以利用多目标架构的强大功能,并在我们的共享项目中访问特定于平台的 API。那么我们还需要 Effects 吗?不需要了,因为我们可以访问我们所需要的所有平台的所有代码和 API。

那么让我们谈谈在 .NET MAUI 中自定义一个控件的所有可能性以及在此过程中您可以遇到的一些障碍。为此,我们将自定义 Image 控件,添加对呈现的图像进行着色的功能。

注意:如果您想使用 Effects ,.NET MAUI仍然支持,但不建议使用

源代码参考来自 .NET MAUI Community Toolkit 的IconTintColor

自定义现有控件 

要向现有控件添加额外的功能,需要我们对其进行扩展并添加所需的功能。

让我们创建一个新控件,class ImageTintColor : Image 并添加一个新的


public class ImageTintColor : Image
{
    public static readonly BindableProperty TintColorProperty =
        BindableProperty.Create(nameof(TintColor), typeof(Color), typeof(ImageTintColor), propertyChanged: OnTintColorChanged);

    public Color? TintColor
    {
        get => (Color?)GetValue(TintColorProperty);
        set => SetValue(TintColorProperty, value);
    }

    static void OnTintColorChanged(BindableObject bindable, object oldValue, object newValue)
    {
        // ...
    }
}

熟悉 Xamarin.Forms 的人会认识到这一点;它与您将在 Xamarin.Forms 应用程序中编写的代码几乎相同。

.NET MAUI 平台特定的 API 工作将在 OnTintColorChanged 委托上进行。让我们来看看。


public class ImageTintColor : Image
{
    public static readonly BindableProperty TintColorProperty =
        BindableProperty.Create(nameof(TintColor), typeof(Color), typeof(ImageTintColor), propertyChanged: OnTintColorChanged);

    public Color? TintColor
    {
        get => (Color?)GetValue(TintColorProperty);
        set => SetValue(TintColorProperty, value);
    }

    static void OnTintColorChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var control = (ImageTintColor)bindable;
        var tintColor = control.TintColor;

        if (control.Handler is null || control.Handler.PlatformView is null)
        {
            // 执行 Handler 且 PlatformView 为 null 时的解决方法
            control.HandlerChanged += OnHandlerChanged;
            return;
        }

        if (tintColor is not null)
        {
#if ANDROID
            // 注意 Android.Widget.ImageView 的使用,它是一个 Android 特定的 API
            // 您可以在这里找到`ApplyColor`的Android实现:https://github.com/pictos/MFCC/blob/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60/MFCC/TintColorExtension.android.cs#L9-L12
            ImageExtensions.ApplyColor((Android.Widget.ImageView)control.Handler.PlatformView, tintColor);
#elif IOS
            // 注意 UIKit.UIImage 的使用,它是一个 iOS 特定的 API
            // 您可以在这里找到`ApplyColor`的iOS实现:https://github.com/pictos/MFCC/blob/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60/MFCC/TintColorExtension.ios.cs#L7-L11
            ImageExtensions.ApplyColor((UIKit.UIImageView)control.Handler.PlatformView, tintColor);
#endif
        }
        else
        {
#if ANDROID
            // 注意 Android.Widget.ImageView 的使用,它是一个 Android 特定的 API
            // 您可以在这里找到 `ClearColor` 的 Android 实现:https://github.com/pictos/MFCC/blob/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60/MFCC/TintColorExtension.android.cs#L14-L17
            ImageExtensions.ClearColor((Android.Widget.ImageView)control.Handler.PlatformView);
#elif IOS
            // 注意 UIKit.UIImage 的使用,它是一个 iOS 特定的 API
            // 您可以在这里找到`ClearColor`的iOS实现:https://github.com/pictos/MFCC/blob/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60/MFCC/TintColorExtension.ios.cs#L13-L16
            ImageExtensions.ClearColor((UIKit.UIImageView)control.Handler.PlatformView);
#endif
        }

        void OnHandlerChanged(object s, EventArgs e)
        {
            OnTintColorChanged(control, oldValue, newValue);
            control.HandlerChanged -= OnHandlerChanged;
        }
    }
}

因为 .NET MAUI 使用多目标,我们可以访问平台的详细信息并按照我们想要的方式自定义控件。ImageExtensions.ApplyColor 和 ImageExtensions.ClearColor 方法是添加或删除图像色调的辅助方法。

您可能会注意到 Handler 和 PlatformView 的 null 检查。这可能是您在使用过程中遇到的第一个阻碍。在创建和实例化 Image 控件并调用 BindableProperty 的 PropertyChanged 委托时,Handler 可以为 null。因此,如果不进行 null 检查,代码将抛出 NullReferenceException。这听起来像一个bug,但它实际上是一个特性!这使 .NET MAUI 工程团队能够保持与 Xamarin.Forms 上的控件相同的生命周期,从而避免从 Forms 迁移到 .NET MAUI 的应用程序的一些重大更改。

现在我们已经完成了所有设置,可以在 ContentPage 中使用控件了。在下面的代码片段中,您可以看到如何在 XAML 中使用它:

<ContentPage x:Class="MyMauiApp.ImageControl"             xmlns="http://schemas.microsoft.com/dotnet/2021/maui"             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"             xmlns:local="clr-namespace:MyMauiApp"             Title="ImageControl"             BackgroundColor="White">
            <local:ImageTintColor x:Name="ImageTintColorControl"                                  Source="shield.png"                                  TintColor="Orange" /></ContentPage>

使用附加属性和 PropertyMapper 

自定义控件的另一种方法是使用 AttachedProperties,当您不需要将其绑定到特定的自定义控件时是 使用BindableProperty

下面是我们如何为 TintColor 创建一个 AttachedProperty:


public static class TintColorMapper
{
    public static readonly BindableProperty TintColorProperty = BindableProperty.CreateAttached("TintColor", typeof(Color), typeof(Image), null);

    public static Color GetTintColor(BindableObject view) => (Color)view.GetValue(TintColorProperty);

    public static void SetTintColor(BindableObject view, Color? value) => view.SetValue(TintColorProperty, value);

    public static void ApplyTintColor()
    {
        // ...
    }
}

同样,我们在 Xamarin.Forms 上为 AttachedProperty 提供了样板,但如您所见,我们没有 PropertyChanged 委托。为了处理属性更改,我们将使用 ImageHandler 中的 Mapper。您可以在任何级别添加 Mapper,因为成员是静态的。我选择在 TintColorMapper 类中执行此操作,如下所示。

public static class TintColorMapper
{
     public static readonly BindableProperty TintColorProperty = BindableProperty.CreateAttached("TintColor", typeof(Color), typeof(Image), null);

    public static Color GetTintColor(BindableObject view) => (Color)view.GetValue(TintColorProperty);

    public static void SetTintColor(BindableObject view, Color? value) => view.SetValue(TintColorProperty, value);

    public static void ApplyTintColor()
    {
        ImageHandler.Mapper.Add("TintColor", (handler, view) =>
        {
            var tintColor = GetTintColor((Image)handler.VirtualView);

            if (tintColor is not null)
            {
#if ANDROID
                // 注意 Android.Widget.ImageView 的使用,它是一个 Android 特定的 API
                // 您可以在这里找到`ApplyColor`的Android实现:https://github.com/pictos/MFCC/blob/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60/MFCC/TintColorExtension.android.cs#L9-L12
                ImageExtensions.ApplyColor((Android.Widget.ImageView)control.Handler.PlatformView, tintColor);
#elif IOS
                // 注意 UIKit.UIImage 的使用,它是一个 iOS 特定的 API
                // 您可以在这里找到`ApplyColor`的iOS实现:https://github.com/pictos/MFCC/blob/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60/MFCC/TintColorExtension.ios.cs#L7-L11
                ImageExtensions.ApplyColor((UIKit.UIImageView)handler.PlatformView, tintColor);
#endif
            }
            else
            {
#if ANDROID
                // 注意 Android.Widget.ImageView 的使用,它是一个 Android 特定的 API
                // 您可以在这里找到 `ClearColor` 的 Android 实现:https://github.com/pictos/MFCC/blob/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60/MFCC/TintColorExtension.android.cs#L14-L17
                ImageExtensions.ClearColor((Android.Widget.ImageView)handler.PlatformView);
#elif IOS
                // 注意 UIKit.UIImage 的使用,它是一个 iOS 特定的 API
                // 您可以在这里找到`ClearColor`的iOS实现:https://github.com/pictos/MFCC/blob/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60/MFCC/TintColorExtension.ios.cs#L13-L16
                ImageExtensions.ClearColor((UIKit.UIImageView)handler.PlatformView);
#endif
            }
        });
    }
}

代码与之前显示的几乎相同,只是使用了另一个 API 实现,在本例中是 AppendToMapping 方法。如果您不想要这种行为,可以改用 CommandMapper,它将在属性更改或操作发生时触发。

请注意,当我们处理 Mapper 和 CommandMapper 时,我们将为项目中使用该处理程序的所有控件添加此行为。在这种情况下,所有Image控件都会触发此代码。在某些情况下这可能并不是您想要的,如果您需要更具体的方法, PlatformBehavior 方法将会非常适合。

现在我们已经设置好了所有内容,可以在页面中使用控件了,在下面的代码片段中,您可以看到如何在 XAML 中使用它。

<ContentPage x:Class="MyMauiApp.ImageControl"             xmlns="http://schemas.microsoft.com/dotnet/2021/maui"             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"             xmlns:local="clr-namespace:MyMauiApp"             Title="ImageControl"             BackgroundColor="White">
            <Image x:Name="Image"                   local:TintColorMapper.TintColor="Fuchsia"                   Source="shield.png" /></ContentPage>

使用平台行为

PlatformBehavior 是在 .NET MAUI 上创建的新 API,它让您在需要以安全的方式访问平台特有的 API 时,可以更轻松地自定义控件(这是安全的因为它确保 Handler 和 PlatformView 不为 null )。它有两种方法来重写OnAttachedTo 和 OnDetachedFrom。此 API 用于替换 Xamarin.Forms 中的 Effect API 并利用多目标体系结构。

在此示例中,我们将使用部分类来实现特定于平台的 API:

//文件名 : ImageTintColorBehavior.cs

public partial class IconTintColorBehavior 
{
    public static readonly BindableProperty TintColorProperty =
        BindableProperty.Create(nameof(TintColor), typeof(Color), typeof(IconTintColorBehavior), propertyChanged: OnTintColorChanged);

    public Color? TintColor
    {
        get => (Color?)GetValue(TintColorProperty);
        set => SetValue(TintColorProperty, value);
    }
}

上面的代码将被我们所针对的所有平台编译。

现在让我们看看 Android 平台的代码:

//文件名: ImageTintColorBehavior.android.cs

public partial class IconTintColorBehavior : PlatformBehavior<Image, ImageView> 
// 注意 ImageView 的使用,它是 Android 特定的 API{
    protected override void OnAttachedTo(Image bindable, ImageView platformView) =>
        ImageExtensions.ApplyColor(bindable, platformView); 
// 您可以在这里找到`ApplyColor`的Android实现:https://github.com/pictos/MFCC/blob/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60/MFCC/TintColorExtension.android.cs#L9-L12

    protected override void OnDetachedFrom(Image bindable, ImageView platformView) =>
        ImageExtensions.ClearColor(platformView); 
// 您可以在这里找到 `ClearColor` 的 Android 实现:https://github.com/pictos/MFCC/blob/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60/MFCC/TintColorExtension.android.cs#L14-L17
}

这是 iOS 平台的代码:


//文件名: ImageTintColorBehavior.ios.cs

public partial class IconTintColorBehavior : PlatformBehavior<Image, UIImageView> 
// 注意 UIImageView 的使用,它是一个 iOS 特定的 API
{
    protected override void OnAttachedTo(Image bindable, UIImageView platformView) => 
        ImageExtensions.ApplyColor(bindable, platformView); 
// 你可以在这里找到`ApplyColor`的iOS实现:https://github.com/pictos/MFCC/blob/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60/MFCC/TintColorExtension.ios.cs#L7-L11

    protected override void OnDetachedFrom(Image bindable, UIImageView platformView) => 
        ImageExtensions.ClearColor(platformView); 
// 你可以在这里找到`ClearColor`的iOS实现:https://github.com/pictos/MFCC/blob/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60/MFCC/TintColorExtension.ios.cs#L13-L16
}

正如您所看到的,我们不需要关心是否 Handler 为 null ,因为 PlatformBehavior<T, U> 会为我们处理。

我们可以指定此行为涵盖的平台特有的 API 的类型。如果您想为多个类型应用控件,则无需指定平台视图的类型(例如,使用 PlatformBehavior<T> );您可能想在多个控件中应用您的行为,在这种情况下,platformView 将是 Android 上的 PlatformBehavior<View> 和 iOS 上的 PlatformBehavior<UIView>。

而且用法更好,您只需要调用 Behavior 即可:

<ContentPage x:Class="MyMauiApp.ImageControl"             xmlns="http://schemas.microsoft.com/dotnet/2021/maui"             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"             xmlns:local="clr-namespace:MyMauiApp"             Title="ImageControl"             BackgroundColor="White">
            <Image x:Name="Image"                   Source="shield.png">                <Image.Behaviors>                    <local:IconTintColorBehavior TintColor="Fuchsia">                </Image.Behaviors>            </Image></ContentPage>

注意:当 Handler 与 VirtualView 断开连接时,即触发 Unloaded 事件时,PlatformBehavior 将调用 OnDetachedFromBehavior API 不会自动调用 OndetachedFrom 方法,作为开发者需要自己处理。

总结

在这篇文章中,我们讨论了自定义控件以及与平台特有的 API 交互的各种方式。没有正确或错误的方法,所有这些都是有效的解决方案,您只需要看看哪种方法更适合您的情况。我想说的是,在大多数情况下,您会想要使用 PlatformBehavior,因为它旨在使用多目标方法并确保在控件不再使用时清理资源。要了解更多信息,请查看有关自定义控件的文档。

关注微软开发者MSDN了解更多

点击了解更多~文章来源地址https://www.toymoban.com/news/detail-479862.html

到了这里,关于在 .NET MAUI 中如何更好地自定义控件的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Maui中基本控件目录

    基本控件介绍 控件名 中文名称 说明 Button 按钮 与WPF中的基础用法无太大变化 CheckBox 单选框 与WPF中的基础用法无太大变化 ListView 列表 类似WPF中列表控件“ListBox” ImageButton 图片按钮 WPF中没有该控件,通常需要开发者手动实现,MAUI中已经包含在基础控件中。 Entry 输入框 类似

    2024年02月07日
    浏览(23)
  • c#WPF 自定义UI控件学习,vb.net界面UI美化

    最近项目中运用到了WPF处理三维软件,在C/S结构中WPF做UI还是有很多优越性,简单的学了一点WPF知识,成功的完成项目目标。项目过度阶段对于WPF的一些基本特点有了进一步了解 。至此花费一点时间研究研究WPF控件。 为以后的项目开发中提供一些可观的资源也是不错的。 目

    2024年02月20日
    浏览(38)
  • [MAUI]在.NET MAUI中实现可拖拽排序列表

    .NET MAUI 中提供了拖放(drag-drop)手势识别器,允许用户通过拖动手势来移动控件。在这篇文章中,我们将学习如何使用拖放手势识别器来实现可拖拽排序列表。在本例中,列表中显示不同大小的磁贴(Tile)并且可以拖拽排序。 使用.NET MAU实现跨平台支持,本项目可运行于Andro

    2024年02月12日
    浏览(35)
  • [MAUI]在.NET MAUI中复刻苹果Cover Flow

    @ 目录 原理 3D旋转 平行变换 创建3D变换控件 绘制封面图片 应用3D旋转 应用平行变换 绘制倒影 创建绑定属性 创建绑定数据 创建布局 计算位置 计算3D旋转 创建动效 项目地址 Cover Flow是iTunes和Finder中的一个视图选项,允许用户使用水平滚动的图像查看他们的音乐库或文件。

    2024年02月05日
    浏览(32)
  • .NET MAUI 性能提升

    .NET多平台应用程序UI (MAUI)将android、iOS、macOS和Windows API统一为一个API,这样你就可以编写一个应用程序在许多平台上本机运行。我们专注于提高您的日常生产力以及您的应用程序的性能。我们认为,开发人员生产率的提高不应该以应用程序性能为代价。 应用程序的大小也是如

    2024年02月07日
    浏览(34)
  • [MAUI]深入了解.NET MAUI Blazor与Vue的混合开发

    .NET MAUI结合Vue的混合开发可以使用更加熟悉的Vue的语法代替Blazor语法,你现有项目不必重写。之前写过一篇 [MAUI] 在.NET MAUI中结合Vue实现混合开发 ,其中介绍了如何创建一个vue应用并将其打包至MAUI项目,这种方式依赖vue-cli创建和打包静态站点,好处是可以使用Node.js 的构建但

    2024年02月08日
    浏览(32)
  • 宣布 .NET MAUI 支持 .NET 7 Release Candidate 2

    支持 .NET 7 Release Candidate 2的 .NET 多平台应用程序 UI (MAUI) 现在可在 Windows 和 Mac 上的 Visual Studio 17.4 Preview 4 中使用。RC2 的主要主题是质量和对带有 iOS 16 的 Xcode 14 的 .NET 支持。此版本包含在生产中使用的上线支持许可证。 在相关新闻中,还为 MSAL.NET 和 App Center(预览版)提供

    2024年02月10日
    浏览(32)
  • .NET MAUI 安卓 UI 资源设置

    本文主要介绍使用 MAUI 开发安卓应用时,如何更换和处理 UI 资源:应用名称,图标,主题配色,状态栏,闪屏。 平常比较喜欢看小说,但是不知道从何时起,已经找不到一个纯粹的本地小说阅读器了。也能理解,毕竟不能只靠爱心发电,在线资源也就算了,我本地的 TXT 你也

    2024年02月10日
    浏览(30)
  • 【C#/.NET】MAUI上的依赖注入

    ​         在移动应用开发中,依赖注入是一项非常重要的技术,它可以帮助我们简化代码结构、提高可维护性并增加测试覆盖率。在最新的.NET跨平台框架MAUI中,我们也可以利用依赖注入来构建高效的应用程序架构。本文将详细介绍在MAUI上如何使用依赖注入,旨在帮助

    2024年02月11日
    浏览(26)
  • Visual Studio 2022 正式支持 .NET MAUI 开发

    我们很高兴地宣布 Visual Studio 2022 正式支持 .NET MAUI 开发。现在,您可以使用 .NET 更快地构建跨平台原生客户端应用程序,并将它们从单个代码库发布到 Android、iOS、macOS 和 Windows。 此版本还提供了 .NET MAUI SDK 的最新稳定性改进,这是自 2022 年 5 月 正式发布(GA)发布以来的第

    2024年02月11日
    浏览(33)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包