Personalizzazione di un elemento ViewCell
ViewCell Xamarin.Forms è una cella che può essere aggiunta a un controllo ListView o TableView, che contiene una visualizzazione definita dallo sviluppatore. Questo articolo illustra come creare un renderer personalizzato per un elemento ViewCell ospitato all'interno di un Xamarin.Forms controllo ListView. In questo modo i calcoli di layout non vengono chiamati ripetutamente durante lo Xamarin.Forms scorrimento di ListView.
Ogni Xamarin.Forms cella ha un renderer a corredo per ogni piattaforma che crea un'istanza di un controllo nativo. ViewCell
Quando un oggetto viene sottoposto a rendering da un'applicazioneXamarin.Forms, in iOS viene creata un'istanza della ViewCellRenderer
classe , che a sua volta crea un'istanza di un controllo nativoUITableViewCell
. Nella piattaforma Android la classe ViewCellRenderer
crea un'istanza di un controllo View
nativo. Nella piattaforma UWP (Universal Windows Platform) la classe ViewCellRenderer
crea un'istanza di un controllo DataTemplate
nativo. Per altre informazioni sulle classi di controllo native e del renderer a cui Xamarin.Forms viene eseguito il mapping dei controlli, vedere Classi di base del renderer e controlli nativi.
Il diagramma seguente illustra la relazione tra la classe ViewCell
e i controlli nativi corrispondenti che la implementano:
È possibile sfruttare il processo di rendering per implementare personalizzazioni specifiche della piattaforma creando un renderer personalizzato per una classe ViewCell
in ogni piattaforma. Il processo per eseguire questa operazione è il seguente:
- Creare una Xamarin.Forms cella personalizzata.
- Utilizzare la cella personalizzata da Xamarin.Forms.
- Creare il renderer personalizzato per la cella in ogni piattaforma.
Ogni elemento verrà ora illustrato a sua volta, per implementare un NativeCell
renderer che sfrutta un layout specifico della piattaforma per ogni cella ospitata all'interno di un Xamarin.FormsListView
controllo. In questo modo i calcoli di Xamarin.Forms layout vengono chiamati ripetutamente durante ListView
lo scorrimento.
Creazione della cella personalizzata
Per creare un controllo cella personalizzato, è possibile sottoclassare la classe ViewCell
come illustrato nell'esempio di codice seguente:
public class NativeCell : ViewCell
{
public static readonly BindableProperty NameProperty =
BindableProperty.Create ("Name", typeof(string), typeof(NativeCell), "");
public string Name {
get { return (string)GetValue (NameProperty); }
set { SetValue (NameProperty, value); }
}
public static readonly BindableProperty CategoryProperty =
BindableProperty.Create ("Category", typeof(string), typeof(NativeCell), "");
public string Category {
get { return (string)GetValue (CategoryProperty); }
set { SetValue (CategoryProperty, value); }
}
public static readonly BindableProperty ImageFilenameProperty =
BindableProperty.Create ("ImageFilename", typeof(string), typeof(NativeCell), "");
public string ImageFilename {
get { return (string)GetValue (ImageFilenameProperty); }
set { SetValue (ImageFilenameProperty, value); }
}
}
La classe NativeCell
viene creata nel progetto di libreria .NET Standard e definisce l'API per la cella personalizzata. La cella personalizzata espone le proprietà Name
, Category
e ImageFilename
che possono essere visualizzate usando il data binding. Per altre informazioni sul data binding, vedere Data Binding Basics (Nozioni di base sul data binding).
Uso della cella personalizzata
Per fare riferimento alla cella personalizzata NativeCell
in XAML nel progetto di libreria .NET Standard, è possibile dichiarare uno spazio dei nomi per il percorso e usare il prefisso dello spazio dei nomi nell'elemento cella personalizzata. Nell'esempio di codice riportato di seguito viene illustrato come la cella personalizzata NativeCell
può essere usata da una pagina XAML:
<ContentPage ...
xmlns:local="clr-namespace:CustomRenderer;assembly=CustomRenderer"
...>
...
<ContentPage.Content>
<StackLayout>
<Label Text="Xamarin.Forms native cell" HorizontalTextAlignment="Center" />
<ListView x:Name="listView" CachingStrategy="RecycleElement" ItemSelected="OnItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<local:NativeCell Name="{Binding Name}" Category="{Binding Category}" ImageFilename="{Binding ImageFilename}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Il prefisso dello spazio dei nomi local
può avere qualsiasi nome. I valori clr-namespace
e assembly
devono tuttavia corrispondere ai dettagli del controllo personalizzato. Dopo aver dichiarato lo spazio dei nomi, il prefisso viene usato per fare riferimento alla cella personalizzata.
Nell'esempio di codice riportato di seguito viene illustrato come la cella personalizzata NativeCell
può essere usata da una pagina C#:
public class NativeCellPageCS : ContentPage
{
ListView listView;
public NativeCellPageCS()
{
listView = new ListView(ListViewCachingStrategy.RecycleElement)
{
ItemsSource = DataSource.GetList(),
ItemTemplate = new DataTemplate(() =>
{
var nativeCell = new NativeCell();
nativeCell.SetBinding(NativeCell.NameProperty, "Name");
nativeCell.SetBinding(NativeCell.CategoryProperty, "Category");
nativeCell.SetBinding(NativeCell.ImageFilenameProperty, "ImageFilename");
return nativeCell;
})
};
switch (Device.RuntimePlatform)
{
case Device.iOS:
Padding = new Thickness(0, 20, 0, 0);
break;
case Device.Android:
case Device.UWP:
Padding = new Thickness(0);
break;
}
Content = new StackLayout
{
Children = {
new Label { Text = "Xamarin.Forms native cell", HorizontalTextAlignment = TextAlignment.Center },
listView
}
};
listView.ItemSelected += OnItemSelected;
}
...
}
Un Xamarin.FormsListView
controllo viene utilizzato per visualizzare un elenco di dati, popolato tramite la ItemSource
proprietà . La strategia di memorizzazione nella cache di RecycleElement
tenta di ridurre al minimo il footprint di memoria ListView
e la velocità di esecuzione riciclando le celle dell'elenco. Per altre informazioni, vedere Caching Strategy (Strategia di memorizzazione nella cache).
Ogni riga dell'elenco contiene tre elementi di dati: un nome, una categoria e un nome di file di immagine. Il layout di ogni riga nell'elenco è definito dall'elemento DataTemplate
a cui viene fatto riferimento attraverso la proprietà ListView.ItemTemplate
associabile. DataTemplate
stabilisce che ogni riga di dati dell'elenco sia un elemento NativeCell
che visualizza le relative proprietà Name
, Category
e ImageFilename
usando il data binding. Per altre informazioni sul controllo ListView
, vedere ListView.
Un renderer personalizzato può essere ora aggiunto a ogni progetto di applicazione per personalizzare il layout specifico della piattaforma per ogni cella.
Creazione del renderer personalizzato in ogni piattaforma
Il processo di creazione della classe di renderer personalizzato è il seguente:
- Creare una sottoclasse della classe
ViewCellRenderer
che esegue il rendering della cella personalizzata. - Eseguire l'override del metodo specifico della piattaforma che esegue il rendering della cella personalizzata e scrivere la logica per personalizzarlo.
- Aggiungere un
ExportRenderer
attributo alla classe renderer personalizzata per specificare che verrà usato per eseguire il rendering della Xamarin.Forms cella personalizzata. Questo attributo viene usato per registrare il renderer personalizzato con Xamarin.Forms.
Nota
Per la maggior parte degli Xamarin.Forms elementi, è facoltativo fornire un renderer personalizzato in ogni progetto di piattaforma. Se un renderer personalizzato non è registrato, verrà usato il renderer predefinito per la classe di base del controllo. I renderer personalizzati sono tuttavia necessari in ogni progetto della piattaforma quando si esegue il rendering di un elemento ViewCell.
Il diagramma seguente illustra le responsabilità di ogni progetto nell'applicazione di esempio, insieme alle relazioni tra di essi:
Il rendering della cella NativeCell
personalizzata viene eseguito dalle classi di renderer specifiche della piattaforma che derivano tutte dalla classe ViewCellRenderer
per ogni piattaforma. Di conseguenza il rendering di ogni cella NativeCell
personalizzata viene eseguito con il layout specifico della piattaforma, come illustrato negli screenshot seguenti:
La classe ViewCellRenderer
espone i metodi specifici della piattaforma per il rendering della cella personalizzata, ovvero il metodo GetCell
nella piattaforma iOS, il metodo GetCellCore
nella piattaforma Android e il metodo GetTemplate
nella piattaforma UWP.
Ogni classe renderer personalizzata è decorata con un ExportRenderer
attributo che registra il renderer con Xamarin.Forms. L'attributo accetta due parametri: il nome del tipo della cella di cui viene eseguito il Xamarin.Forms rendering e il nome del tipo del renderer personalizzato. Il prefisso assembly
dell'attributo specifica che l'attributo viene applicato all'intero assembly.
Le sezioni seguenti illustrano l'implementazione della classe renderer personalizzato specifica di ogni piattaforma.
Creazione del renderer personalizzato in iOS
L'esempio di codice seguente illustra il renderer personalizzato per la piattaforma iOS:
[assembly: ExportRenderer(typeof(NativeCell), typeof(NativeiOSCellRenderer))]
namespace CustomRenderer.iOS
{
public class NativeiOSCellRenderer : ViewCellRenderer
{
NativeiOSCell cell;
public override UITableViewCell GetCell(Cell item, UITableViewCell reusableCell, UITableView tv)
{
var nativeCell = (NativeCell)item;
cell = reusableCell as NativeiOSCell;
if (cell == null)
cell = new NativeiOSCell(item.GetType().FullName, nativeCell);
else
cell.NativeCell.PropertyChanged -= OnNativeCellPropertyChanged;
nativeCell.PropertyChanged += OnNativeCellPropertyChanged;
cell.UpdateCell(nativeCell);
return cell;
}
...
}
}
Il metodo GetCell
viene chiamato per compilare ogni cella da visualizzare. Ogni cella è un'istanza di NativeiOSCell
, che definisce il layout della cella e dei relativi dati. L'operazione del metodo GetCell
dipende dalla strategia di memorizzazione nella cache di ListView
:
Quando la strategia di memorizzazione nella cache di
ListView
èRetainElement
, viene richiamato il metodoGetCell
per ogni cella. Viene creata un'istanza diNativeiOSCell
per ogni istanza diNativeCell
inizialmente visualizzata sullo schermo. Mentre l'utente scorre attraversoListView
, vengono nuovamente usate le istanze diNativeiOSCell
. Per altre informazioni sul riutilizzo della cella iOS, vedere Cell Reuse (Riutilizzo della cella).Nota
Questo codice di renderer personalizzato consente di usare di nuovo alcune celle anche se si imposta
ListView
in modo da conservare le celle.I dati visualizzati da ogni istanza di
NativeiOSCell
, appena creata o usata nuovamente, verranno aggiornati con i dati di ogni istanza diNativeCell
dal metodoUpdateCell
.Nota
Il metodo
OnNativeCellPropertyChanged
non verrà mai richiamato se la strategia di memorizzazione nella cache diListView
è impostata in modo da conservare le celle.Quando la strategia di memorizzazione nella cache di
ListView
èRecycleElement
, viene richiamato il metodoGetCell
per ogni cella inizialmente visualizzata sullo schermo. Viene creata un'istanza diNativeiOSCell
per ogni istanza diNativeCell
inizialmente visualizzata sullo schermo. I dati visualizzati da ogni istanza diNativeiOSCell
verranno aggiornati con i dati dell'istanza diNativeCell
dal metodoUpdateCell
. Tuttavia, il metodoGetCell
non viene richiamato quando l'utente scorre nell'oggettoListView
. Verranno invece usate nuovamente le istanze diNativeiOSCell
. Gli eventiPropertyChanged
verranno generati nell'istanza diNativeCell
in caso di modifica dei dati e il gestore eventiOnNativeCellPropertyChanged
aggiornerà i dati in ogni istanza diNativeiOSCell
riusata.
L'esempio di codice riportato di seguito illustra il metodo OnNativeCellPropertyChanged
richiamato quando viene generato un evento PropertyChanged
:
namespace CustomRenderer.iOS
{
public class NativeiOSCellRenderer : ViewCellRenderer
{
...
void OnNativeCellPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var nativeCell = (NativeCell)sender;
if (e.PropertyName == NativeCell.NameProperty.PropertyName)
{
cell.HeadingLabel.Text = nativeCell.Name;
}
else if (e.PropertyName == NativeCell.CategoryProperty.PropertyName)
{
cell.SubheadingLabel.Text = nativeCell.Category;
}
else if (e.PropertyName == NativeCell.ImageFilenameProperty.PropertyName)
{
cell.CellImageView.Image = cell.GetImage(nativeCell.ImageFilename);
}
}
}
}
Questo metodo aggiorna i dati visualizzati dalle istanze di NativeiOSCell
riusate. Viene eseguito un controllo per la proprietà modificata, poiché il metodo può essere chiamato più volte.
La classe NativeiOSCell
definisce il layout per ogni cella come illustra l'esempio di codice seguente:
internal class NativeiOSCell : UITableViewCell, INativeElementView
{
public UILabel HeadingLabel { get; set; }
public UILabel SubheadingLabel { get; set; }
public UIImageView CellImageView { get; set; }
public NativeCell NativeCell { get; private set; }
public Element Element => NativeCell;
public NativeiOSCell(string cellId, NativeCell cell) : base(UITableViewCellStyle.Default, cellId)
{
NativeCell = cell;
SelectionStyle = UITableViewCellSelectionStyle.Gray;
ContentView.BackgroundColor = UIColor.FromRGB(255, 255, 224);
CellImageView = new UIImageView();
HeadingLabel = new UILabel()
{
Font = UIFont.FromName("Cochin-BoldItalic", 22f),
TextColor = UIColor.FromRGB(127, 51, 0),
BackgroundColor = UIColor.Clear
};
SubheadingLabel = new UILabel()
{
Font = UIFont.FromName("AmericanTypewriter", 12f),
TextColor = UIColor.FromRGB(38, 127, 0),
TextAlignment = UITextAlignment.Center,
BackgroundColor = UIColor.Clear
};
ContentView.Add(HeadingLabel);
ContentView.Add(SubheadingLabel);
ContentView.Add(CellImageView);
}
public void UpdateCell(NativeCell cell)
{
HeadingLabel.Text = cell.Name;
SubheadingLabel.Text = cell.Category;
CellImageView.Image = GetImage(cell.ImageFilename);
}
public UIImage GetImage(string filename)
{
return (!string.IsNullOrWhiteSpace(filename)) ? UIImage.FromFile("Images/" + filename + ".jpg") : null;
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
HeadingLabel.Frame = new CGRect(5, 4, ContentView.Bounds.Width - 63, 25);
SubheadingLabel.Frame = new CGRect(100, 18, 100, 20);
CellImageView.Frame = new CGRect(ContentView.Bounds.Width - 63, 5, 33, 33);
}
}
Questa classe definisce i controlli usati per eseguire il rendering del contenuto della cella e il relativo layout. La classe implementa l'interfaccia INativeElementView
, che è obbligatoria quando ListView
usa di nuovo la strategia di memorizzazione nella cache di RecycleElement
. Questa interfaccia specifica che la classe deve implementare la proprietà Element
, che deve restituire i dati della cella personalizzata per le celle riciclate.
Il costruttore NativeiOSCell
inizializza l'aspetto delle proprietà HeadingLabel
, SubheadingLabel
e CellImageView
. Queste proprietà vengono usate per visualizzare i dati archiviati nell'istanza di NativeCell
, con il metodo UpdateCell
chiamato per impostare il valore di ogni proprietà. Inoltre, quando ListView
usa la strategia di memorizzazione nella cache di RecycleElement
, i dati visualizzati dalle proprietà HeadingLabel
, SubheadingLabel
e CellImageView
possono essere aggiornati dal metodo OnNativeCellPropertyChanged
nel renderer personalizzato.
Il layout della cella viene eseguito dall'override di LayoutSubviews
, che imposta le coordinate di HeadingLabel
, SubheadingLabel
e CellImageView
all'interno della cella.
Creazione del renderer personalizzato in Android
L'esempio di codice seguente illustra il renderer personalizzato per la piattaforma Android:
[assembly: ExportRenderer(typeof(NativeCell), typeof(NativeAndroidCellRenderer))]
namespace CustomRenderer.Droid
{
public class NativeAndroidCellRenderer : ViewCellRenderer
{
NativeAndroidCell cell;
protected override Android.Views.View GetCellCore(Cell item, Android.Views.View convertView, ViewGroup parent, Context context)
{
var nativeCell = (NativeCell)item;
Console.WriteLine("\t\t" + nativeCell.Name);
cell = convertView as NativeAndroidCell;
if (cell == null)
{
cell = new NativeAndroidCell(context, nativeCell);
}
else
{
cell.NativeCell.PropertyChanged -= OnNativeCellPropertyChanged;
}
nativeCell.PropertyChanged += OnNativeCellPropertyChanged;
cell.UpdateCell(nativeCell);
return cell;
}
...
}
}
Il metodo GetCellCore
viene chiamato per compilare ogni cella da visualizzare. Ogni cella è un'istanza di NativeAndroidCell
, che definisce il layout della cella e dei relativi dati. L'operazione del metodo GetCellCore
dipende dalla strategia di memorizzazione nella cache di ListView
:
Quando la strategia di memorizzazione nella cache di
ListView
èRetainElement
, viene richiamato il metodoGetCellCore
per ogni cella. Viene creato un elementoNativeAndroidCell
per ogni istanza diNativeCell
inizialmente visualizzata sullo schermo. Mentre l'utente scorre attraversoListView
, vengono nuovamente usate le istanze diNativeAndroidCell
. Per altre informazioni sul riutilizzo delle celle di Android, vedere Row View Re-use (Riutilizzo della vista righe).Nota
Si noti che questo codice di renderer personalizzato consente di usare di nuovo alcune celle anche se si imposta
ListView
in modo da conservare le celle.I dati visualizzati da ogni istanza di
NativeAndroidCell
, appena creata o usata nuovamente, verranno aggiornati con i dati di ogni istanza diNativeCell
dal metodoUpdateCell
.Nota
Si noti che benché il metodo
OnNativeCellPropertyChanged
venga richiamato quando si impostaListView
in modo da conservare le celle, non aggiornerà i valori della proprietàNativeAndroidCell
.Quando la strategia di memorizzazione nella cache di
ListView
èRecycleElement
, viene richiamato il metodoGetCellCore
per ogni cella inizialmente visualizzata sullo schermo. Viene creata un'istanza diNativeAndroidCell
per ogni istanza diNativeCell
inizialmente visualizzata sullo schermo. I dati visualizzati da ogni istanza diNativeAndroidCell
verranno aggiornati con i dati dell'istanza diNativeCell
dal metodoUpdateCell
. Tuttavia, il metodoGetCellCore
non viene richiamato quando l'utente scorre nell'oggettoListView
. Verranno invece usate nuovamente le istanze diNativeAndroidCell
. Gli eventiPropertyChanged
verranno generati nell'istanza diNativeCell
in caso di modifica dei dati e il gestore eventiOnNativeCellPropertyChanged
aggiornerà i dati in ogni istanza diNativeAndroidCell
riusata.
L'esempio di codice riportato di seguito illustra il metodo OnNativeCellPropertyChanged
richiamato quando viene generato un evento PropertyChanged
:
namespace CustomRenderer.Droid
{
public class NativeAndroidCellRenderer : ViewCellRenderer
{
...
void OnNativeCellPropertyChanged(object sender, PropertyChangedEventArgs e)
{
var nativeCell = (NativeCell)sender;
if (e.PropertyName == NativeCell.NameProperty.PropertyName)
{
cell.HeadingTextView.Text = nativeCell.Name;
}
else if (e.PropertyName == NativeCell.CategoryProperty.PropertyName)
{
cell.SubheadingTextView.Text = nativeCell.Category;
}
else if (e.PropertyName == NativeCell.ImageFilenameProperty.PropertyName)
{
cell.SetImage(nativeCell.ImageFilename);
}
}
}
}
Questo metodo aggiorna i dati visualizzati dalle istanze di NativeAndroidCell
riusate. Viene eseguito un controllo per la proprietà modificata, poiché il metodo può essere chiamato più volte.
La classe NativeAndroidCell
definisce il layout per ogni cella come illustra l'esempio di codice seguente:
internal class NativeAndroidCell : LinearLayout, INativeElementView
{
public TextView HeadingTextView { get; set; }
public TextView SubheadingTextView { get; set; }
public ImageView ImageView { get; set; }
public NativeCell NativeCell { get; private set; }
public Element Element => NativeCell;
public NativeAndroidCell(Context context, NativeCell cell) : base(context)
{
NativeCell = cell;
var view = (context as Activity).LayoutInflater.Inflate(Resource.Layout.NativeAndroidCell, null);
HeadingTextView = view.FindViewById<TextView>(Resource.Id.HeadingText);
SubheadingTextView = view.FindViewById<TextView>(Resource.Id.SubheadingText);
ImageView = view.FindViewById<ImageView>(Resource.Id.Image);
AddView(view);
}
public void UpdateCell(NativeCell cell)
{
HeadingTextView.Text = cell.Name;
SubheadingTextView.Text = cell.Category;
// Dispose of the old image
if (ImageView.Drawable != null)
{
using (var image = ImageView.Drawable as BitmapDrawable)
{
if (image != null)
{
if (image.Bitmap != null)
{
image.Bitmap.Dispose();
}
}
}
}
SetImage(cell.ImageFilename);
}
public void SetImage(string filename)
{
if (!string.IsNullOrWhiteSpace(filename))
{
// Display new image
Context.Resources.GetBitmapAsync(filename).ContinueWith((t) =>
{
var bitmap = t.Result;
if (bitmap != null)
{
ImageView.SetImageBitmap(bitmap);
bitmap.Dispose();
}
}, TaskScheduler.FromCurrentSynchronizationContext());
}
else
{
// Clear the image
ImageView.SetImageBitmap(null);
}
}
}
Questa classe definisce i controlli usati per eseguire il rendering del contenuto della cella e il relativo layout. La classe implementa l'interfaccia INativeElementView
, che è obbligatoria quando ListView
usa di nuovo la strategia di memorizzazione nella cache di RecycleElement
. Questa interfaccia specifica che la classe deve implementare la proprietà Element
, che deve restituire i dati della cella personalizzata per le celle riciclate.
Il costruttore NativeAndroidCell
ingrandisce il layout NativeAndroidCell
e inizializza le proprietà HeadingTextView
, SubheadingTextView
e ImageView
per i controlli nel layout ingrandito. Queste proprietà vengono usate per visualizzare i dati archiviati nell'istanza di NativeCell
, con il metodo UpdateCell
chiamato per impostare il valore di ogni proprietà. Inoltre, quando ListView
usa la strategia di memorizzazione nella cache di RecycleElement
, i dati visualizzati dalle proprietà HeadingTextView
, SubheadingTextView
e ImageView
possono essere aggiornati dal metodo OnNativeCellPropertyChanged
nel renderer personalizzato.
L'esempio di codice seguente illustra la definizione del layout per il file di layout NativeAndroidCell.axml
:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:background="@drawable/CustomSelector">
<LinearLayout
android:id="@+id/Text"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingLeft="10dip">
<TextView
android:id="@+id/HeadingText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FF7F3300"
android:textSize="20dip"
android:textStyle="italic" />
<TextView
android:id="@+id/SubheadingText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="14dip"
android:textColor="#FF267F00"
android:paddingLeft="100dip" />
</LinearLayout>
<ImageView
android:id="@+id/Image"
android:layout_width="48dp"
android:layout_height="48dp"
android:padding="5dp"
android:src="@drawable/icon"
android:layout_alignParentRight="true" />
</RelativeLayout>
Questo layout specifica che due controlli TextView
e un controllo ImageView
vengono usati per visualizzare il contenuto della cella. I due controlli TextView
sono orientati verticalmente all'interno di un controllo LinearLayout
e tutti i controlli sono contenuti in un RelativeLayout
.
Creazione del renderer personalizzato in UWP
L'esempio di codice seguente illustra il renderer personalizzato per la piattaforma UWP:
[assembly: ExportRenderer(typeof(NativeCell), typeof(NativeUWPCellRenderer))]
namespace CustomRenderer.UWP
{
public class NativeUWPCellRenderer : ViewCellRenderer
{
public override Windows.UI.Xaml.DataTemplate GetTemplate(Cell cell)
{
return App.Current.Resources["ListViewItemTemplate"] as Windows.UI.Xaml.DataTemplate;
}
}
}
Il metodo GetTemplate
viene chiamato per restituire la cella da sottoporre a rendering per ogni riga di dati dell'elenco. Crea un elemento DataTemplate
per ogni istanza di NativeCell
che verrà visualizzata sullo schermo, con DataTemplate
che definisce l'aspetto e il contenuto della cella.
DataTemplate
è archiviato nel dizionario risorse a livello di applicazione, come illustrato nell'esempio di codice seguente:
<DataTemplate x:Key="ListViewItemTemplate">
<Grid Background="LightYellow">
<Grid.Resources>
<local:ConcatImageExtensionConverter x:Name="ConcatImageExtensionConverter" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.40*" />
<ColumnDefinition Width="0.40*"/>
<ColumnDefinition Width="0.20*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.ColumnSpan="2" Foreground="#7F3300" FontStyle="Italic" FontSize="22" VerticalAlignment="Top" Text="{Binding Name}" />
<TextBlock Grid.RowSpan="2" Grid.Column="1" Foreground="#267F00" FontWeight="Bold" FontSize="12" VerticalAlignment="Bottom" Text="{Binding Category}" />
<Image Grid.RowSpan="2" Grid.Column="2" HorizontalAlignment="Left" VerticalAlignment="Center" Source="{Binding ImageFilename, Converter={StaticResource ConcatImageExtensionConverter}}" Width="50" Height="50" />
<Line Grid.Row="1" Grid.ColumnSpan="3" X1="0" X2="1" Margin="30,20,0,0" StrokeThickness="1" Stroke="LightGray" Stretch="Fill" VerticalAlignment="Bottom" />
</Grid>
</DataTemplate>
DataTemplate
specifica i controlli usati per visualizzare il contenuto della cella, nonché il layout e l'aspetto. Due controlli TextBlock
e un controllo Image
vengono usati per visualizzare il contenuto della cella usando il data binding. Inoltre, viene usata un'istanza di ConcatImageExtensionConverter
per concatenare l'estensione file .jpg
a ogni nome di file di immagine. Ciò garantisce che il controllo Image
sia in grado di caricare l'immagine ed eseguirne il rendering quando è impostata la relativa proprietà Source
.
Riepilogo
Questo articolo ha illustrato come creare un renderer personalizzato per un ViewCell
oggetto ospitato all'interno di un Xamarin.FormsListView
controllo . In questo modo i calcoli di Xamarin.Forms layout vengono chiamati ripetutamente durante ListView
lo scorrimento.