网站 内容 营销,网站搜索框如何做,网站开发工具怎么改内容,深圳易百讯网站建设公司点击上方蓝字关注我们#xff08;本文阅读时间#xff1a;10分钟)今天#xff0c;我想谈谈并向您展示在.NET MAUI中完全自定义控件的方法。在查看 .NET MAUI 之前#xff0c;让我们回到几年前#xff0c;回到 Xamarin.Forms 时代。那时#xff0c;我们有很多自定义控件的… 点击上方蓝字关注我们本文阅读时间10分钟)今天我想谈谈并向您展示在.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。.NET MAUIhttps://dotnet.microsoft.com/zh-cn/apps/maui?ocidAID3052907Xamarin.Formshttps://docs.microsoft.com/zh-cn/xamarin/xamarin-forms/?WT.mc_iddotnet-0000-bramin?ocidAID3052907Behaviorshttps://docs.microsoft.com/zh-cn/xamarin/xamarin-forms/app-fundamentals/behaviors/?WT.mc_iddotnet-0000-bramin?ocidAID3052907Effectshttps://docs.microsoft.com/zh-cn/xamarin/xamarin-forms/app-fundamentals/effects/introduction?WT.mc_iddotnet-0000-bramin?ocidAID3052907自定义渲染器https://docs.microsoft.com/zh-cn/xamarin/xamarin-forms/app-fundamentals/custom-renderer/?WT.mc_iddotnet-0000-bramin?ocidAID3052907IconTintColorhttps://github.com/CommunityToolkit/Maui/tree/main/src/CommunityToolkit.Maui/Behaviors/PlatformBehaviors/IconTintColor自定义现有控件 要向现有控件添加额外的功能需要我们对其进行扩展并添加所需的功能。让我们创建一个新控件class ImageTintColor : Image 并添加一个新的 BindableProperty我们将利用它来更改 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-L12ImageExtensions.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-L11ImageExtensions.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-L17ImageExtensions.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-L16ImageExtensions.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:ClassMyMauiApp.ImageControlxmlnshttp://schemas.microsoft.com/dotnet/2021/mauixmlns:xhttp://schemas.microsoft.com/winfx/2009/xamlxmlns:localclr-namespace:MyMauiAppTitleImageControlBackgroundColorWhitelocal:ImageTintColor x:NameImageTintColorControlSourceshield.pngTintColorOrange /
/ContentPage使用附加属性和 PropertyMapper 自定义控件的另一种方法是使用 AttachedProperties当您不需要将其绑定到特定的自定义控件时是 使用BindableProperty。下面是我们如何为 TintColor 创建一个 AttachedPropertypublic 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-L12ImageExtensions.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-L11ImageExtensions.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-L17ImageExtensions.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-L16ImageExtensions.ClearColor((UIKit.UIImageView)handler.PlatformView);
#endif}});}
}代码与之前显示的几乎相同只是使用了另一个 API 实现在本例中是 AppendToMapping 方法。如果您不想要这种行为可以改用 CommandMapper它将在属性更改或操作发生时触发。请注意当我们处理 Mapper 和 CommandMapper 时我们将为项目中使用该处理程序的所有控件添加此行为。在这种情况下所有Image控件都会触发此代码。在某些情况下这可能并不是您想要的如果您需要更具体的方法 PlatformBehavior 方法将会非常适合。现在我们已经设置好了所有内容可以在页面中使用控件了在下面的代码片段中您可以看到如何在 XAML 中使用它。ContentPage x:ClassMyMauiApp.ImageControlxmlnshttp://schemas.microsoft.com/dotnet/2021/mauixmlns:xhttp://schemas.microsoft.com/winfx/2009/xamlxmlns:localclr-namespace:MyMauiAppTitleImageControlBackgroundColorWhiteImage x:NameImagelocal:TintColorMapper.TintColorFuchsiaSourceshield.png /
/ContentPage使用PlatformBehaviorPlatformBehavior 是在 .NET MAUI 上创建的新 API它让您在需要以安全的方式访问平台特有的 API 时可以更轻松地自定义控件这是安全的因为它确保 Handler 和 PlatformView 不为 null 。它有两种方法来重写OnAttachedTo 和 OnDetachedFrom。此 API 用于替换 Xamarin.Forms 中的 Effect API 并利用多目标体系结构。在此示例中我们将使用部分类来实现特定于平台的 API//文件名 : ImageTintColorBehavior.cspublic 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.cspublic partial class IconTintColorBehavior : PlatformBehaviorImage, 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-L12protected 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.cspublic partial class IconTintColorBehavior : PlatformBehaviorImage, 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-L11protected 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 因为 PlatformBehaviorT, U 会为我们处理。我们可以指定此行为涵盖的平台特有的 API 的类型。如果您想为多个类型应用控件则无需指定平台视图的类型例如使用 PlatformBehaviorT 您可能想在多个控件中应用您的行为在这种情况下platformView 将是 Android 上的 PlatformBehaviorView 和 iOS 上的 PlatformBehaviorUIView。而且用法更好您只需要调用 Behavior 即可ContentPage x:ClassMyMauiApp.ImageControlxmlnshttp://schemas.microsoft.com/dotnet/2021/mauixmlns:xhttp://schemas.microsoft.com/winfx/2009/xamlxmlns:localclr-namespace:MyMauiAppTitleImageControlBackgroundColorWhiteImage x:NameImageSourceshield.pngImage.Behaviorslocal:IconTintColorBehavior TintColorFuchsia/Image.Behaviors/Image
/ContentPage注意当 Handler 与 VirtualView 断开连接时即触发 Unloaded 事件时PlatformBehavior 将调用 OnDetachedFrom。Behavior API 不会自动调用 OnDetachedFrom 方法作为开发者需要自己处理。总结在这篇文章中我们讨论了自定义控件以及与平台特有的 API 交互的各种方式。没有正确或错误的方法所有这些都是有效的解决方案您只需要看看哪种方法更适合您的情况。我想说的是在大多数情况下您会想要使用 PlatformBehavior因为它旨在使用多目标方法并确保在控件不再使用时清理资源。要了解更多信息请查看有关自定义控件的文档。有关自定义控件的文档https://docs.microsoft.com/zh-cn/dotnet/maui/user-interface/handlers/customize?ocidAID3052907有关更多的MAUI workshop请查看https://github.com/dotnet-presentations/dotnet-maui-workshop/blob/main/README.zh-cn.md谢谢你读完了本文相信你一定有一些感想、观点、问题想要表达。欢迎在评论区畅所欲言期待听到你的“声音”哦同时喜欢的内容也不要忘记转发给你的小伙伴们谢谢你的支持长按识别二维码关注微软中国MSDN点击「阅读原文」了解更多~