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

Browse sample. 샘플 찾아보기

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

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

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

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

Important

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

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

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

컨트롤 사용자 지정

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

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

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

Entry handler architecture.

클래스의 EntryHandler 속성 매퍼는 Entry 플랫폼 간 컨트롤 속성을 네이티브 뷰 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에서 게인 OnEntryHandlerChanged 포커스를 구현 Entry 하는 네이티브 뷰에서 발생하는 네이티브 뷰 이벤트를 구독합니다.

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

HandlerChanging 이벤트는 플랫폼 간 컨트롤에서 기존 처리기가 제거되기 전과 플랫폼 간 컨트롤에 대한 새 처리기가 생성되기 전에 발생합니다. 따라서 해당 이벤트 처리기는 네이티브 이벤트 구독을 제거하고 다른 클린 수행되어야 하는 위치입니다. HandlerChangingEventArgs 이 이벤트와 함께 제공되는 개체에는 OldHandler 각각 이전 및 NewHandler 새 처리기로 설정되는 속성이 있습니다. 이 예제에서 이벤트는 iOS, OnEntryHandlerChanging 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);
}

Important

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

이 예제에서 두 이벤트 처리기는 이름이 지정된 ChangedHandler 부분 메서드를 호출하고 ChangingHandler, 서명은 플랫폼 간 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 클래스 및 메서드를 참조하세요. 플랫폼 코드를 플랫폼 폴더의 하위 폴더에 배치할 필요가 없도록 다중 대상 지정을 구성하는 방법에 대한 자세한 내용은 다중 대상 지정 구성을 참조하세요.