처리기를 사용하여 컨트롤 사용자 지정

샘플을 찾아봅니다. 샘플 찾아보기

처리기를 사용자 지정하여 컨트롤의 API를 통해 가능한 사용자 지정을 넘어 플랫폼 간 컨트롤의 모양과 동작을 보강할 수 있습니다. 플랫폼 간 컨트롤에 대한 네이티브 보기를 수정하는 이 사용자 지정은 다음 방법 중 하나를 사용하여 처리기에 대한 매퍼를 수정하여 수행됩니다.

  • PrependToMapping.NET MAUI 컨트롤 매핑이 적용되기 전에 처리기에 대한 매퍼를 수정하는 입니다.
  • ModifyMapping- 기존 매핑을 수정합니다.
  • AppendToMapping.NET MAUI 컨트롤 매핑이 적용된 후 처리기에 대한 매퍼를 수정하는 입니다.

이러한 각 메서드에는 두 개의 인수가 필요한 동일한 서명이 있습니다.

  • string기반 키입니다. .NET MAUI에서 제공하는 매핑 중 하나를 수정하는 경우 .NET MAUI에서 사용하는 키를 지정해야 합니다. .NET MAUI 컨트롤 매핑에 사용되는 키 값은 인터페이스 및 속성 이름(예 nameof(IEntry.IsPassword): )을 기반으로 합니다. 각 플랫폼 간 컨트롤을 추상화하는 인터페이스 및 해당 속성은 여기에서 찾을 수 있습니다. 그렇지 않으면 이 키는 형식에 의해 노출되는 속성의 이름에 해당할 필요가 없는 임의의 값일 수 있습니다. 예를 들어 을 MyCustomization 키로 지정할 수 있으며, 네이티브 뷰 수정이 사용자 지정으로 수행됩니다.
  • Action 처리기 사용자 지정을 수행하는 메서드를 나타내는 입니다. 는 Action 두 개의 인수를 지정합니다.
    • handler 사용자 지정되는 처리기의 인스턴스를 제공하는 인수입니다.
    • view 처리기가 구현하는 플랫폼 간 컨트롤의 인스턴스를 제공하는 인수입니다.

중요

처리기 사용자 지정은 전역이며 특정 컨트롤 인스턴스로 범위가 지정되지 않습니다. 처리기 사용자 지정은 앱의 어디에서나 발생할 수 있습니다. 처리기가 사용자 지정되면 앱의 모든 위치에서 해당 형식의 모든 컨트롤에 영향을 줍니다.

각 처리기 클래스는 해당 속성을 통해 플랫폼 간 컨트롤에 대한 네이티브 뷰를 노출합니다 PlatformView . 이 속성에 액세스하여 네이티브 뷰 속성을 설정하고, 네이티브 뷰 메서드를 호출하고, 네이티브 뷰 이벤트를 구독할 수 있습니다. 또한 처리기에 의해 구현된 플랫폼 간 컨트롤은 해당 VirtualView 속성을 통해 노출됩니다.

조건부 컴파일을 사용하여 플랫폼별 처리기를 플랫폼 기반의 다중 대상 코드로 사용자 지정할 수 있습니다. 또는 부분 클래스를 사용하여 코드를 플랫폼별 폴더 및 파일로 구성할 수 있습니다. 조건부 컴파일에 대한 자세한 내용은 조건부 컴파일을 참조하세요.

컨트롤 사용자 지정

.NET MAUI Entry 보기는 인터페이스를 구현하는 한 줄 텍스트 입력 컨트롤입니다 IEntry . 는 EntryHandler 각 플랫폼에 Entry 대해 다음과 같은 네이티브 보기에 보기를 매핑합니다.

  • iOS/Mac Catalyst: UITextField
  • Android: AppCompatEditText
  • Windows: TextBox

다음 다이어그램에서는 뷰가 를 Entry 통해 EntryHandler네이티브 뷰에 매핑되는 방법을 보여 줍니다.

항목 처리기 아키텍처.

속성 매퍼는 Entry 클래스에서 EntryHandler 플랫폼 간 컨트롤 속성을 네이티브 뷰 API에 매핑합니다. 이렇게 하면 속성이 에 Entry설정되면 기본 네이티브 뷰가 필요에 따라 업데이트됩니다.

속성 매퍼는 각 플랫폼에서 사용자 지정 Entry 하도록 수정할 수 있습니다.

namespace CustomizeHandlersDemo.Views;

public partial class CustomizeEntryPage : ContentPage
{
    public CustomizeEntryPage()
    {
        InitializeComponent();
        ModifyEntry();
    }

    void ModifyEntry()
    {
        Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("MyCustomization", (handler, view) =>
        {
#if ANDROID
            handler.PlatformView.SetSelectAllOnFocus(true);
#elif IOS || MACCATALYST
            handler.PlatformView.EditingDidBegin += (s, e) =>
            {
                handler.PlatformView.PerformSelector(new ObjCRuntime.Selector("selectAll"), null, 0.0f);
            };
#elif WINDOWS
            handler.PlatformView.GotFocus += (s, e) =>
            {
                handler.PlatformView.SelectAll();
            };
#endif
        });
    }
}

이 예제에서 사용자 지정은 Entry 페이지 클래스에서 발생합니다. 따라서 의 인스턴스가 만들어지면 Android, iOS 및 Windows의 CustomizeEntryPage 모든 Entry 컨트롤이 사용자 지정됩니다. 사용자 지정은 각 플랫폼의 플랫폼 간 컨트롤에 매핑되는 네이티브 보기에 대한 액세스를 제공하는 처리기 PlatformView 속성에 액세스하여 수행됩니다. 네이티브 코드는 포커스를 얻을 때 의 모든 텍스트를 Entry 선택하여 처리기를 사용자 지정합니다.

매퍼에 대한 자세한 내용은 매퍼를 참조하세요.

특정 컨트롤 인스턴스 사용자 지정

처리기는 전역이며 컨트롤에 대한 처리기를 사용자 지정하면 앱에서 동일한 형식의 모든 컨트롤이 사용자 지정됩니다. 그러나 특정 컨트롤 인스턴스에 대한 처리기는 컨트롤을 서브클래싱한 다음 컨트롤이 서브클래싱된 형식인 경우에만 기본 컨트롤 형식에 대한 처리기를 수정하여 사용자 지정할 수 있습니다. 예를 들어 여러 Entry 컨트롤이 포함된 페이지에서 특정 Entry 컨트롤을 사용자 지정하려면 먼저 컨트롤을 Entry 서브클래스해야 합니다.

namespace CustomizeHandlersDemo.Controls
{
    internal class MyEntry : Entry
    {
    }
}

그런 다음, 속성 매퍼를 EntryHandler통해 를 사용자 지정하여 인스턴스에 대해서만 원하는 수정을 MyEntry 수행할 수 있습니다.

Microsoft.Maui.Handlers.EntryHandler.Mapper.AppendToMapping("MyCustomization", (handler, view) =>
{
    if (view is MyEntry)
    {
#if ANDROID
        handler.PlatformView.SetSelectAllOnFocus(true);
#elif IOS || MACCATALYST
        handler.PlatformView.EditingDidBegin += (s, e) =>
        {
            handler.PlatformView.PerformSelector(new ObjCRuntime.Selector("selectAll"), null, 0.0f);
        };
#elif WINDOWS
        handler.PlatformView.GotFocus += (s, e) =>
        {
            handler.PlatformView.SelectAll();
        };
#endif
    }
});

처리기 사용자 지정이 클래스에서 App 수행되는 경우 처리기 수정에 따라 앱의 모든 MyEntry 인스턴스가 사용자 지정됩니다.

처리기 수명 주기를 사용하여 컨트롤 사용자 지정

모든 처리기 기반 .NET MAUI는 지원 HandlerChangingHandlerChanged 이벤트를 제어합니다. 이 HandlerChanged 이벤트는 플랫폼 간 컨트롤을 구현하는 네이티브 뷰를 사용할 수 있고 초기화할 때 발생합니다. 이벤트는 HandlerChanging 컨트롤의 처리기가 플랫폼 간 컨트롤에서 제거될 때 발생합니다. 처리기 수명 주기 이벤트에 대한 자세한 내용은 처리기 수명 주기를 참조하세요.

처리기 수명 주기를 사용하여 처리기 사용자 지정을 수행할 수 있습니다. 예를 들어 네이티브 뷰 이벤트를 구독 및 구독 취소하려면 사용자 지정되는 플랫폼 간 컨트롤에서 및 HandlerChanging 이벤트에 대한 HandlerChanged 이벤트 처리기를 등록해야 합니다.

<Entry HandlerChanged="OnEntryHandlerChanged"
       HandlerChanging="OnEntryHandlerChanging" />

처리기는 조건부 컴파일을 사용하거나 부분 클래스를 사용하여 코드를 플랫폼별 폴더 및 파일로 구성하여 플랫폼별로 사용자 지정할 수 있습니다. 각 방법은 포커스를 얻을 때 모든 텍스트가 선택되도록 을 사용자 지정하여 Entry 차례로 설명합니다.

조건부 컴파일

HandlerChanging 이벤트에 대한 HandlerChanged 이벤트 처리기를 포함하는 코드 숨김 파일은 조건부 컴파일을 사용하는 다음 예제에 나와 있습니다.

#if ANDROID
using AndroidX.AppCompat.Widget;
#elif IOS || MACCATALYST
using UIKit;
#elif WINDOWS
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml;
#endif

namespace CustomizeHandlersDemo.Views;

public partial class CustomizeEntryHandlerLifecyclePage : ContentPage
{
    public CustomizeEntryHandlerLifecyclePage()
    {
        InitializeComponent();
    }

    void OnEntryHandlerChanged(object sender, EventArgs e)
    {
        Entry entry = sender as Entry;
#if ANDROID
        (entry.Handler.PlatformView as AppCompatEditText).SetSelectAllOnFocus(true);
#elif IOS || MACCATALYST
        (entry.Handler.PlatformView as UITextField).EditingDidBegin += OnEditingDidBegin;
#elif WINDOWS
        (entry.Handler.PlatformView as TextBox).GotFocus += OnGotFocus;
#endif
    }

    void OnEntryHandlerChanging(object sender, HandlerChangingEventArgs e)
    {
        if (e.OldHandler != null)
        {
#if IOS || MACCATALYST
            (e.OldHandler.PlatformView as UITextField).EditingDidBegin -= OnEditingDidBegin;
#elif WINDOWS
            (e.OldHandler.PlatformView as TextBox).GotFocus -= OnGotFocus;
#endif
        }
    }

#if IOS || MACCATALYST                   
    void OnEditingDidBegin(object sender, EventArgs e)
    {
        var nativeView = sender as UITextField;
        nativeView.PerformSelector(new ObjCRuntime.Selector("selectAll"), null, 0.0f);
    }
#elif WINDOWS
    void OnGotFocus(object sender, RoutedEventArgs e)
    {
        var nativeView = sender as TextBox;
        nativeView.SelectAll();
    }
#endif
}

HandlerChanged 이벤트는 플랫폼 간 컨트롤을 구현하는 네이티브 뷰가 만들어지고 초기화된 후에 발생합니다. 따라서 해당 이벤트 처리기는 네이티브 이벤트 구독을 수행해야 하는 위치입니다. 이렇게 하려면 네이 PlatformView 티브 이벤트에 액세스할 수 있도록 처리기의 속성을 네이티브 뷰의 형식 또는 기본 형식으로 캐스팅해야 합니다. 이 예제에서 iOS, Mac Catalyst 및 Windows에서 이벤트는 게인 OnHandlerChanged 포커스를 구현 Entry 하는 네이티브 뷰가 발생할 때 발생하는 네이티브 보기 이벤트를 구독합니다.

OnEditingDidBeginOnGotFocus 이벤트 처리기는 해당 플랫폼의 에 대한 네이 Entry 티브 보기에 액세스하고 에 있는 Entry모든 텍스트를 선택합니다.

이벤트는 HandlerChanging 기존 처리기가 플랫폼 간 컨트롤에서 제거되기 전과 플랫폼 간 컨트롤에 대한 새 처리기가 생성되기 전에 발생합니다. 따라서 해당 이벤트 처리기는 네이티브 이벤트 구독을 제거하고 다른 정리를 수행해야 하는 위치입니다. 이 이벤트와 함께 제공되는 개체에는 HandlerChangingEventArgsOldHandler 각각 이전 및 새 처리기로 설정되는 및 NewHandler 속성이 있습니다. 이 예제에서 이벤트는 iOS, OnHandlerChanging Mac Catalyst 및 Windows의 네이티브 뷰 이벤트에 대한 구독을 제거합니다.

partial 클래스

조건부 컴파일을 사용하는 대신 부분 클래스를 사용하여 컨트롤 사용자 지정 코드를 플랫폼별 폴더 및 파일로 구성할 수도 있습니다. 이 방법을 사용하면 사용자 지정 코드가 플랫폼 간 부분 클래스 및 플랫폼별 partial 클래스로 구분됩니다. 다음 예제에서는 플랫폼 간 부분 클래스를 보여줍니다.

namespace CustomizeHandlersDemo.Views;

public partial class CustomizeEntryPartialMethodsPage : ContentPage
{
    public CustomizeEntryPartialMethodsPage()
    {
        InitializeComponent();
    }

    partial void ChangedHandler(object sender, EventArgs e);
    partial void ChangingHandler(object sender, HandlerChangingEventArgs e);

    void OnEntryHandlerChanged(object sender, EventArgs e) => ChangedHandler(sender, e);
    void OnEntryHandlerChanging(object sender, HandlerChangingEventArgs e) => ChangingHandler(sender, e);
}

중요

플랫폼 간 부분 클래스는 프로젝트의 Platforms 자식 폴더에 배치하면 안 됩니다.

이 예제에서 두 이벤트 처리기는 및 라는 ChangedHandler 부분 메서드를 호출하며 ChangingHandler, 해당 시그니처는 플랫폼 간 partial 클래스에 정의됩니다. 그런 다음 부분 메서드 구현은 플랫폼별 partial 클래스에 정의됩니다. 이 클래스는 빌드 시스템이 특정 플랫폼용으로 빌드할 때 네이티브 코드만 빌드하도록 올바른 Platforms 자식 폴더에 배치해야 합니다. 예를 들어 다음 코드는 프로젝트의 Platforms>Windows 폴더에 있는 클래스를 보여 CustomizeEntryPartialMethodsPage 줍니다.

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;

namespace CustomizeHandlersDemo.Views
{
    public partial class CustomizeEntryPartialMethodsPage : ContentPage
    {
        partial void ChangedHandler(object sender, EventArgs e)
        {
            Entry entry = sender as Entry;
            (entry.Handler.PlatformView as TextBox).GotFocus += OnGotFocus;
        }

        partial void ChangingHandler(object sender, HandlerChangingEventArgs e)
        {
            if (e.OldHandler != null)
            {
                (e.OldHandler.PlatformView as TextBox).GotFocus -= OnGotFocus;
            }
        }

        void OnGotFocus(object sender, RoutedEventArgs e)
        {
            var nativeView = sender as TextBox;
            nativeView.SelectAll();
        }
    }
}

이 방법의 장점은 조건부 컴파일이 필요하지 않으며 부분 메서드를 각 플랫폼에서 구현할 필요가 없다는 것입니다. 구현이 플랫폼에서 제공되지 않으면 메서드와 메서드에 대한 모든 호출이 컴파일 시간에 제거됩니다. 부분 메서드에 대한 자세한 내용은 Partial 메서드를 참조하세요.

.NET MAUI 프로젝트에서 Platforms 폴더의 조직에 대한 자세한 내용은 Partial 클래스 및 메서드를 참조하세요. 플랫폼 폴더의 하위 폴더에 플랫폼 코드를 배치할 필요가 없도록 다중 대상 지정을 구성하는 방법에 대한 자세한 내용은 다중 대상 지정 구성을 참조하세요.