简体   繁体   English

.net maui 中的自定义控件和渲染器会发生什么?

[英]What will happen to custom controls and Renderers in .net maui?

In my Current Xamarin.Forms projects I have created many Renderers for different requirements.在我当前的 Xamarin.Forms 项目中,我为不同的要求创建了许多渲染器。 Now in September maui is coming and we have to migrate our projects to that.现在在 9 月,毛伊岛即将到来,我们必须将我们的项目迁移到那里。 So in that what will happen to Renderers?那么,渲染器会发生什么? Is it going to work as it is or we will not need that Renderers?它会按原样工作还是我们不需要渲染器?

In .NET MAUI the concept of renderers will go away and is replaced by the handler architecture.在 .NET MAUI 中,渲染器的概念将消失,取而代之的是处理程序架构。 Renderers were too tightly coupled to the actual controls and the supported platforms, on top of that (or maybe because of that) they were slow as they relied on reflection etc.渲染器与实际控件和支持的平台的耦合过于紧密,最重要的是(或者可能正因为如此)它们依赖于反射等,因此速度很慢。

A big part of why .NET MAUI is so exciting is that this whole architecture will change. .NET MAUI 如此令人兴奋的很大一部分原因在于整个架构将会发生变化。 Now, instead of the renderers there will be handlers which basically handle one property at a time and there is an abstraction added between the handler and the control.现在,将有处理程序代替渲染器,它们基本上一次处理一个属性,并且在处理程序和控件之间添加了一个抽象。 This is a big deal because now backends (think iOS, Android, but also SkiaSharp or others) can be implemented more easily.这很重要,因为现在可以更轻松地实现后端(想想 iOS、Android,还有 SkiaSharp 或其他)。

As to your question: there are different migration paths possible.至于您的问题:可能有不同的迁移路径。 You can reuse your current existing custom renderers as they are.您可以按原样重用当前现有的自定义渲染器。 There should be very minimal code changes.代码更改应该非常少。 The Xamarin.Forms/.NET MAUI team has worked hard to implement a compatibility layer to pull that off. Xamarin.Forms/.NET MAUI 团队一直在努力实现兼容层来实现这一目标。 However, you will get limited benefits from switching to .NET MAUI, but it will buy you some time to rewrite those renderers and still be able to release your app.但是,您从切换到 .NET MAUI 中获得的好处有限,它会为您争取一些时间来重写这些渲染器,并且仍然能够发布您的应用程序。 Although there should be plenty of time, Xamarin.Forms is still supported until November 2022.尽管应该有足够的时间,但在 2022 年 11 月之前仍然支持 Xamarin.Forms。

Without going into too much technical details, reusing your current renderer might look like this in your Startup.cs class in your .NET MAUI project (full code here ):在不涉及太多技术细节的情况下,在 .NET MAUI 项目的Startup.cs类中重用当前渲染器可能如下所示(完整代码在此处):


public void Configure(IAppHostBuilder appBuilder)
{
    appBuilder
        .UseMauiApp<App>()
        .ConfigureMauiHandlers(handlers =>
              {
#if __ANDROID__
        handlers.AddCompatibilityRenderer(typeof(Label), typeof(MAUICustomRendererSample.Platforms.Android.MyLabelRenderer));
#endif
        })
        .ConfigureFonts(fonts =>
        {
            fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
        });
}

Then, of course, there is still the possibility to override the handler behavior.然后,当然,仍然有可能覆盖处理程序的行为。 There are multiple ways to do this depending on your needs.根据您的需要,有多种方法可以做到这一点。 To just override one property, that is now much easier than in the renderer era.只覆盖一个属性,现在比渲染器时代容易得多。 For instance, have a look at the code below to just change the background color of a Button (full code here ):例如,看看下面的代码来改变按钮的背景颜色(完整代码在这里):

public void Configure(IAppHostBuilder appBuilder)
{
    appBuilder
        .UseMauiApp<App>()
        .ConfigureFonts(fonts =>
        {
            fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
        });

    #if __ANDROID__
                Microsoft.Maui.Handlers.ButtonHandler.ButtonMapper["MyCustomization"] = (handler, view) =>
                {
                    handler.NativeView.SetBackgroundColor(Android.Graphics.Color.Green);
                };
    #endif
}

To create a whole custom control that effort is about the same only the approach is different.要创建一个完整的自定义控件,工作量大致相同,只是方法不同。 More samples of transitions from Forms to .NET MAUI can be found here in this example from Javier who has been working on Forms and now .NET MAUI.更多从 Forms 到 .NET MAUI 的转换示例可以在这个示例中找到,该示例来自 Javier,他一直致力于 Forms 和现在的 .NET MAUI。 Most of the other things (behaviors, effects, etc.) are not more than replacing some namespaces in your code and it all should work.大多数其他事情(行为、效果等)只不过是替换代码中的一些命名空间,这一切都应该有效。

As a cherry on top there is a Upgrade Assistant that will help you with the most tasks of changing your project and renaming namespaces etc. More info on that can be found in this months Community Standup session .最重要的是有一个升级助手,它将帮助您完成更改项目和重命名命名空间等大多数任务。更多信息可以在本月的社区站立会议中找到。

Depending on the project size and time/budget you have available I would personally first port everything with the Forms compatibility layer.根据您可用的项目规模和时间/预算,我个人首先会使用 Forms 兼容性层移植所有内容。 That should require the least amount of effort.这应该需要最少的努力。 Check if everything still works as intended and you should be able to move forward with that.检查一切是否仍按预期工作,您应该能够继续前进。 After that, one by one start replacing your renderers with the new handler structure.之后,一一开始用新的处理程序结构替换您的渲染器。

Lastly;最后; be aware that all the third-party libraries that you may be using also all need to be ready for .NET 6 and/or .NET MAUI so make sure to check those before you start upgrading.请注意,您可能使用的所有第三方库也都需要为 .NET 6 和/或 .NET MAUI 做好准备,因此请务必在开始升级之前检查这些库。

Other good resource to keep your eye on is the Docs that are being worked on.其他值得关注的好资源是正在处理的文档

In.Net Maui here is the complete custom handlers for the record reference. In.Net Maui 这里是记录参考的完整自定义处理程序。

Create Interface base IView //ICustomButton.cs创建接口基IView //ICustomButton.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CustomButtonLib.Controls
{
    public interface ICustomButton : IView
    {
        public string Text { get; }
        public string TexColor { get; }
    }
}

CustomButton BindableProperty //CustomButton.cs CustomButton BindableProperty //CustomButton.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CustomButtonLib.Controls
{
    public class CustomButton : View, ICustomButton
    {
        public static readonly BindableProperty TextProperty =
            BindableProperty.Create(
                nameof(Text), 
                typeof(string),
                typeof(CustomButton),
                string.Empty);

        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

        public static readonly BindableProperty TextColorProperty =
           BindableProperty.Create(
              nameof(TextColor),
              typeof(Color),
              typeof(CustomButton),
              Colors.ForestGreen);

        public Color TextColor
        {
            get { return (Color)GetValue(TextProperty); }
            set { SetValue(TextColorProperty, value); }
        }
    }
}

Create a partial CustomButtonHandler //CustomButtonHandler.cs创建部分CustomButtonHandler //CustomButtonHandler.cs

using CustomButtonLib.Controls;
using Microsoft.Maui.Handlers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CustomButtonLib.Handlers
{
    public partial class CustomButtonHandler
    {
        public static PropertyMapper<ICustomButton, CustomButtonHandler> CustomButtonMapper = 
            new PropertyMapper<ICustomButton, CustomButtonHandler>(ViewHandler.ViewMapper)
        {
            [nameof(ICustomButton.Text)] = MapText,
            [nameof(ICustomButton.TextColor)] = MapTextColor,
        };

        public CustomButtonHandler() : base(CustomButtonMapper)
        {
        }

        public CustomButtonHandler(PropertyMapper mapper = null) : base(mapper ?? CustomButtonMapper)
        {
        }
    }
}

.NetStandard partial class //CustomButtonHandler.Standard.cs .NetStandard 部分类 //CustomButtonHandler.Standard.cs

using CustomButtonLib.Controls;
using Microsoft.Maui.Handlers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CustomButtonLib.Handlers
{
    public partial class CustomButtonHandler : ViewHandler<ICustomButton, object>
    {
        protected override object CreatePlatformView()
        {
            throw new NotImplementedException();
        }

        public static void MapText(CustomButtonHandler handler, ICustomButton iCustomButton) 
        { 
        }

        public static void MapTextColor(CustomButtonHandler handler, ICustomButton iCustomButton) 
        {
        }
    }
}

Create specific handler in Platform Folder (Ex. Windows) //CustomButtonHandler.cs在平台文件夹(例如 Windows)//CustomButtonHandler.cs 中创建特定的处理程序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Maui.Handlers;
using Microsoft.UI.Xaml;

namespace CustomButtonLib.Handlers
{
    public partial class CustomButtonHandler : ViewHandler<ICustomButton, FrameworkElement>
    {
        protected override FrameworkElement CreatePlatformView()
        {
            return new Microsoft.UI.Xaml.Controls.Button();
        }

        protected override void ConnectHandler(Microsoft.UI.Xaml.Controls.Button nativeView)
        {
            // Subscribe to events
            base.ConnectHandler(nativeView);
        }

        protected override void DisconnectHandler(Microsoft.UI.Xaml.Controls.ButtonnativeView)
        {
            // Unsubscribe from events
            base.DisconnectHandler(nativeView);
        }

        public static void MapText(CustomButtonHandler handler, ICustomButton iCustomButton)
        {
            if (handler != null && 
                handler.PlatformView != null &&
                handler.PlatformView is Microsoft.UI.Xaml.Controls.Button bttn)
            {
                bttn.Content = iCustomButton.Text;
            }
        }

        [MissingMapper] // Add this to indicate if not available on this platform.
        public static void MapTextColor(CustomButtonHandler handler, ICustomButton iCustomButton) 
        {
        }

    }
}

Continue On Other Platforms for successful build.继续在其他平台上成功构建。

Optional => Add Project sdk ItemGroups, so no need to Add Platform Directive.可选 => 添加 Project sdk ItemGroups,因此无需添加平台指令。 (Ex. #if Windows). (例如#if Windows)。

<ItemGroup Condition="$(TargetFramework.StartsWith('net6.0-ios')) != true ">
        <Compile Remove="Platforms\iOS\*.cs" />
        <None Include="Platforms\iOS\*.cs" />
    </ItemGroup>

    <ItemGroup Condition="$(TargetFramework.StartsWith('net6.0-maccatalyst')) != true ">
        <Compile Remove="Platforms\MacCatalyst\*.cs" />
        <None Include="Platforms\MacCatalyst\*.cs" />
    </ItemGroup>

    <ItemGroup Condition="$(TargetFramework.StartsWith('net6.0-android')) != true ">
        <Compile Remove="Platforms\Android\*.cs" />
        <None Include="Platforms\Android\*.cs" />
    </ItemGroup>

    <ItemGroup Condition="$(TargetFramework.Contains('-windows')) != true ">
        <Compile Remove="Platforms\Windows\*.cs" />
        <None Include="Platforms\Windows\*.cs" />
    </ItemGroup>

    <ItemGroup Condition="$(TargetFramework.StartsWith('net6.0-ios')) == true OR $(TargetFramework.StartsWith('net6.0-maccatalyst')) == true OR $(TargetFramework.StartsWith('net6.0-android')) == true OR $(TargetFramework.Contains('-windows')) == true">
        <Compile Remove="**\*.Standard.cs" />
        <None Include="**\*.Standard.cs" />
        <Compile Remove="**\Standard\**\*.cs" />
        <None Include="**\Standard\**\*.cs" />
    </ItemGroup>



    <!-- ANDROID -->
    <PropertyGroup Condition="$(TargetFramework.StartsWith('net6.0-android'))">
        <DefineConstants>$(DefineConstants);MONOANDROID</DefineConstants>
    </PropertyGroup>

    <!-- IOS -->
    <PropertyGroup Condition=" '$(TargetFramework)' == 'net6.0-ios' ">
        <DefineConstants>$(DefineConstants);IOS</DefineConstants>
    </PropertyGroup>

    <!-- MACCATALYST -->
    <PropertyGroup Condition=" '$(TargetFramework)' == 'net6.0-maccatalyst' ">
        <DefineConstants>$(DefineConstants);MACCATALYST;IOS</DefineConstants>
    </PropertyGroup>

    <!-- WINDOWS -->
    <PropertyGroup Condition="$(TargetFramework.Contains('-windows')) == true ">
        <TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
        <RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
        <DefineConstants>WINDOWS;$(DefineConstants)</DefineConstants>
    </PropertyGroup>

Last Register Custom Button on Builder Services => Extensions构建器服务上的最后注册自定义按钮 => 扩展

        public static MauiAppBuilder ConfigureLibrary(this MauiAppBuilder builder)
        {
            builder
                .ConfigureMauiHandlers(handlers =>
                {
                    handlers.AddLibraryHandlers();
                });
            return builder;
        }

        public static IMauiHandlersCollection AddLibraryHandlers(this IMauiHandlersCollection handlers)
        {
            handlers.AddTransient(typeof(CustomButton), h => new CustomButtonHandler());
            
            return handlers;
        }
// Usage .ConfigureLibrary()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM