Personalizzare i controlli con i gestori
I gestori possono essere personalizzati per aumentare l'aspetto e il comportamento di un controllo multipiattaforma oltre la personalizzazione possibile tramite l'API del controllo. Questa personalizzazione, che modifica le visualizzazioni native per il controllo multipiattaforma, viene ottenuta modificando il mapper per un gestore con uno dei metodi seguenti:
- PrependToMapping, che modifica il mapper per un gestore prima dell'applicazione dei mapping dei controlli MAUI .NET.
- ModifyMapping, che modifica un mapping esistente.
- AppendToMapping, che modifica il mapper per un gestore dopo l'applicazione dei mapping dei controlli MAUI .NET.
Ognuno di questi metodi ha una firma identica che richiede due argomenti:
- Chiave
string
basata su . Quando si modifica uno dei mapping forniti da .NET MAUI, è necessario specificare la chiave usata da .NET MAUI. I valori chiave usati dai mapping dei controlli MAUI .NET sono basati su nomi di interfaccia e proprietà, ad esempionameof(IEntry.IsPassword)
. Le interfacce e le relative proprietà, che astraggono ogni controllo multipiattaforma sono disponibili qui. Questo è il formato di chiave che deve essere usato se si vuole che la personalizzazione del gestore venga eseguita ogni volta che una proprietà cambia. In caso contrario, la chiave può essere un valore arbitrario che non deve corrispondere al nome di una proprietà esposta da un tipo. Ad esempio,MyCustomization
può essere specificato come chiave, con qualsiasi modifica della visualizzazione nativa eseguita come personalizzazione. Tuttavia, una conseguenza di questo formato di chiave è che la personalizzazione del gestore verrà eseguita solo quando il mapper per il gestore viene modificato per la prima volta. - Oggetto Action che rappresenta il metodo che esegue la personalizzazione del gestore. Specifica Action due argomenti:
- Argomento
handler
che fornisce un'istanza del gestore da personalizzare. - Argomento
view
che fornisce un'istanza del controllo multipiattaforma implementato dal gestore.
- Argomento
Importante
Le personalizzazioni del gestore sono globali e non hanno come ambito un'istanza di controllo specifica. La personalizzazione del gestore può essere eseguita ovunque nell'app. Dopo aver personalizzato un gestore, influisce su tutti i controlli di quel tipo, ovunque nell'app.
Ogni classe del gestore espone la visualizzazione nativa per il controllo multipiattaforma tramite la relativa PlatformView proprietà. È possibile accedere a questa proprietà per impostare le proprietà della visualizzazione nativa, richiamare i metodi di visualizzazione nativa e sottoscrivere eventi di visualizzazione nativa. Inoltre, il controllo multipiattaforma implementato dal gestore viene esposto tramite la relativa VirtualView proprietà.
I gestori possono essere personalizzati per ogni piattaforma usando la compilazione condizionale, al codice multi-destinazione basato sulla piattaforma. In alternativa, è possibile usare classi parziali per organizzare il codice in cartelle e file specifici della piattaforma. Per altre informazioni sulla compilazione condizionale, vedere Compilazione condizionale.
Personalizzare un controllo
La visualizzazione MAUI Entry .NET è un controllo input di testo a riga singola che implementa l'interfaccia IEntry . La EntryHandler vista viene mappata Entry alle visualizzazioni native seguenti per ogni piattaforma:
- iOS/Mac Catalyst:
UITextField
- Android:
AppCompatEditText
- Windows:
TextBox
I diagrammi seguenti illustrano come viene eseguito il mapping della Entry vista alle visualizzazioni native tramite EntryHandler:
Il Entry mapper di proprietà, nella classe , esegue il EntryHandler mapping delle proprietà del controllo multipiattaforma all'API di visualizzazione nativa. In questo modo, quando una proprietà è impostata su , Entryla visualizzazione nativa sottostante viene aggiornata in base alle esigenze.
Il mapper di proprietà può essere modificato per personalizzare Entry in ogni piattaforma:
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
});
}
}
In questo esempio la Entry personalizzazione viene eseguita in una classe di pagina. Pertanto, tutti i Entry controlli in Android, iOS e Windows verranno personalizzati dopo la creazione di un'istanza CustomizeEntryPage
di . La personalizzazione viene eseguita accedendo alla proprietà gestori PlatformView , che consente di accedere alla visualizzazione nativa mappata al controllo multipiattaforma in ogni piattaforma. Il codice nativo personalizza quindi il gestore selezionando tutto il testo in Entry quando ottiene lo stato attivo.
Per altre informazioni sui mapper, vedere Mapper.
Personalizzare un'istanza del controllo specifica
I gestori sono globali e la personalizzazione di un gestore per un controllo comporterà la personalizzazione di tutti i controlli dello stesso tipo nell'app. Tuttavia, i gestori per istanze di controllo specifiche possono essere personalizzati sottoclassando il controllo e quindi modificando il gestore per il tipo di controllo di base solo quando il controllo è del tipo sottoclassato. Ad esempio, per personalizzare un controllo specifico Entry in una pagina contenente più Entry controlli, è necessario prima sottoclassare il Entry controllo:
namespace CustomizeHandlersDemo.Controls
{
internal class MyEntry : Entry
{
}
}
È quindi possibile personalizzare , EntryHandler
tramite il relativo mapper di proprietà, per eseguire la modifica desiderata solo per MyEntry
le istanze:
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
}
});
Se la personalizzazione del gestore viene eseguita nella App
classe, tutte MyEntry
le istanze dell'app verranno personalizzate in base alla modifica del gestore.
Personalizzare un controllo usando il ciclo di vita del gestore
Tutti i controlli MAUI basati su gestori supportano HandlerChanging e HandlerChanged eventi. L'evento HandlerChanged viene generato quando la visualizzazione nativa che implementa il controllo multipiattaforma è disponibile e inizializzata. L'evento HandlerChanging viene generato quando il gestore del controllo sta per essere rimosso dal controllo multipiattaforma. Per altre informazioni sugli eventi del ciclo di vita del gestore, vedere Ciclo di vita del gestore.
Il ciclo di vita del gestore può essere usato per eseguire la personalizzazione del gestore. Ad esempio, per sottoscrivere e annullare la sottoscrizione, gli eventi di visualizzazione nativa è necessario registrare i gestori eventi per gli HandlerChanged eventi e HandlerChanging nel controllo multipiattaforma da personalizzare:
<Entry HandlerChanged="OnEntryHandlerChanged"
HandlerChanging="OnEntryHandlerChanging" />
I gestori possono essere personalizzati per ogni piattaforma usando la compilazione condizionale o usando classi parziali per organizzare il codice in cartelle e file specifici della piattaforma. Ogni approccio verrà discusso a sua volta, personalizzando un oggetto Entry in modo che tutto il testo venga selezionato quando ottiene lo stato attivo.
Compilazione condizionale
Il file code-behind contenente i gestori eventi per gli HandlerChanged eventi e HandlerChanging viene illustrato nell'esempio seguente, che usa la compilazione condizionale:
#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
}
L'evento HandlerChanged viene generato dopo la visualizzazione nativa che implementa il controllo multipiattaforma è stato creato e inizializzato. Di conseguenza, il gestore eventi è la posizione in cui devono essere eseguite le sottoscrizioni di eventi native. A tale scopo, è necessario eseguire il cast della PlatformView proprietà del gestore al tipo o al tipo di base della visualizzazione nativa in modo che sia possibile accedere agli eventi nativi. In questo esempio, in iOS, Mac Catalyst e Windows, l'evento OnEntryHandlerChanged
sottoscrive gli eventi di visualizzazione nativa generati quando le visualizzazioni native che implementano lo Entry stato attivo.
I OnEditingDidBegin
gestori eventi e OnGotFocus
accedono alla visualizzazione nativa per l'oggetto Entry nelle rispettive piattaforme e selezionano tutto il Entrytesto presente in .
L'evento HandlerChanging viene generato prima che il gestore esistente venga rimosso dal controllo multipiattaforma e prima che venga creato il nuovo gestore per il controllo multipiattaforma. Di conseguenza, il gestore eventi è la posizione in cui devono essere rimosse le sottoscrizioni di eventi native e deve essere eseguita un'altra pulizia. L'oggetto HandlerChangingEventArgs che accompagna questo evento ha OldHandler proprietà e NewHandler , che verranno impostate rispettivamente sui gestori precedenti e nuovi. In questo esempio, l'evento OnEntryHandlerChanging
rimuove la sottoscrizione agli eventi di visualizzazione nativa in iOS, Mac Catalyst e Windows.
Classi parziali
Invece di usare la compilazione condizionale, è anche possibile usare classi parziali per organizzare il codice di personalizzazione del controllo in cartelle e file specifici della piattaforma. Con questo approccio, il codice di personalizzazione è separato in una classe parziale multipiattaforma e in una classe parziale specifica della piattaforma:
- La classe parziale multipiattaforma definisce in genere i membri, ma non li implementa e viene creato per tutte le piattaforme. Questa classe non deve essere inserita in nessuna delle cartelle figlio Platforms del progetto, perché in questo modo sarebbe una classe specifica della piattaforma.
- La classe parziale specifica della piattaforma implementa in genere i membri definiti nella classe parziale multipiattaforma e viene compilato per una singola piattaforma. Questa classe deve essere inserita nella cartella figlio della cartella Piattaforme per la piattaforma scelta.
L'esempio seguente mostra una classe parziale multipiattaforma:
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);
}
In questo esempio, i due gestori eventi chiamano metodi parziali denominati ChangedHandler
e ChangingHandler
, le cui firme sono definite nella classe parziale multipiattaforma. Le implementazioni parziali del metodo vengono quindi definite nelle classi parziali specifiche della piattaforma, che devono essere inserite nelle cartelle figlio Piattaforme corrette per garantire che il sistema di compilazione tenti di compilare codice nativo solo durante la compilazione per la piattaforma specifica. Ad esempio, il codice seguente mostra la CustomizeEntryPartialMethodsPage
classe nella cartella Platforms>Windows del progetto:
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();
}
}
}
Il vantaggio di questo approccio è che la compilazione condizionale non è necessaria e che i metodi parziali non devono essere implementati in ogni piattaforma. Se un'implementazione non viene fornita in una piattaforma, il metodo e tutte le chiamate al metodo vengono rimosse in fase di compilazione. Per informazioni sui metodi parziali, vedere Metodi parziali.
Per informazioni sull'organizzazione della cartella Platforms in un progetto MAUI .NET, vedere Classi e metodi parziali. Per informazioni su come configurare multitargeting in modo che non sia necessario inserire il codice della piattaforma in sottocartelle della cartella Piattaforme , vedere Configurare multitargeting.