Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
I data binding dell'interfaccia utente dell'app multipiattaforma .NET (.NET MAUI) in genere trasferiscono i dati da una proprietà di origine a una proprietà di destinazione e in alcuni casi dalla proprietà di destinazione alla proprietà di origine. Questo trasferimento è semplice quando le proprietà di origine e di destinazione sono dello stesso tipo o quando un tipo può essere convertito nell'altro tipo tramite una conversione implicita. In caso contrario, deve essere eseguita una conversione del tipo.
Nell'articolo Formattazione stringa è stato illustrato come usare la StringFormat proprietà di un data binding per convertire qualsiasi tipo in una stringa. Per altri tipi di conversioni, è necessario scrivere codice specializzato in una classe che implementa l'interfaccia IValueConverter . Le classi che implementano IValueConverter sono denominate convertitori di valori, ma vengono spesso definite convertitori di associazioni o convertitori di valori di associazione.
Convertitori di valori di associazione
Si supponga di voler definire un data binding in cui la proprietà di origine è di tipo int , ma la proprietà di destinazione è un oggetto bool. Si vuole che questo data binding generi un false valore quando l'origine integer è uguale a 0 e true in caso contrario. Questa operazione può essere ottenuta con una classe che implementa l'interfaccia IValueConverter :
public class IntToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value != 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? 1 : 0;
}
}
Si imposta quindi un'istanza di questa classe sulla proprietà Converter della classe Binding o sulla proprietà Converter dell'estensione di markup Binding. Questa classe diventa parte del data binding.
Il metodo Convert viene chiamato quando i dati vengono spostati dall'origine alla destinazione nei collegamenti OneWay o TwoWay. Il value parametro è l'oggetto o il valore dell'origine di associazione dati. Il metodo deve restituire un valore del tipo della destinazione di associazione dati. Il metodo illustrato di seguito esegue il cast del value parametro a un int e quindi lo confronta con 0 per un bool valore restituito.
Il metodo ConvertBack viene chiamato quando i dati vengono spostati dalla destinazione all'origine nelle associazioni dati TwoWay o OneWayToSource.
ConvertBack esegue la conversione opposta: presuppone che il value parametro sia un bool dalla destinazione e lo converte in un valore di ritorno int per la sorgente.
Annotazioni
Se un data binding include anche un'impostazione StringFormat , il convertitore di valori viene richiamato prima che il risultato venga formattato come stringa.
Nell'esempio seguente viene illustrato come usare questo convertitore di valori in un data binding:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.EnableButtonsPage"
Title="Enable Buttons">
<ContentPage.Resources>
<local:IntToBoolConverter x:Key="intToBool" />
</ContentPage.Resources>
<StackLayout Padding="10, 0">
<Entry x:Name="entry1"
Text=""
Placeholder="enter search term"
VerticalOptions="Center" />
<Button x:DataType="Entry"
Text="Search"
HorizontalOptions="Center"
VerticalOptions="Center"
IsEnabled="{Binding Source={x:Reference entry1},
Path=Text.Length,
Converter={StaticResource intToBool}}" />
<Entry x:Name="entry2"
Text=""
Placeholder="enter destination"
VerticalOptions="Center" />
<Button x:DataType="Entry"
Text="Submit"
HorizontalOptions="Center"
VerticalOptions="Center"
IsEnabled="{Binding Source={x:Reference entry2},
Path=Text.Length,
Converter={StaticResource intToBool}}" />
</StackLayout>
</ContentPage>
In questo esempio, l'istanza di IntToBoolConverter viene creata nel dizionario risorse della pagina. Viene quindi fatto riferimento a un'estensione StaticResource di markup per impostare la proprietà Converter in due data binding. È molto comune condividere i convertitori di dati tra più data binding nella pagina. Se un convertitore di valori viene usato in più pagine dell'applicazione, è possibile crearne un'istanza nel dizionario risorse a livello di applicazione.
In questo esempio viene illustrata una necessità comune quando un'operazione Button viene eseguita in base al testo digitato dall'utente in una Entry visualizzazione. La Text proprietà di ogni Entry oggetto viene inizializzata in una stringa vuota, perché la Text proprietà è null per impostazione predefinita e il data binding non funzionerà in questo caso. Se non è stato digitato alcun elemento in Entry, l'oggetto Button deve essere disabilitato. Ogni Button oggetto contiene un data binding sulla relativa IsEnabled proprietà. L'origine del data binding è la proprietà Length della proprietà Text dell'oggetto corrispondente Entry. Se tale Length proprietà non è 0, il convertitore di valori restituisce true e il Button viene abilitato.
Annotazioni
Se si sa che un convertitore di valori verrà usato solo nelle OneWay associazioni, il ConvertBack metodo può semplicemente restituire null.
Il Convert metodo illustrato in precedenza presuppone che l'argomento value sia di tipo int e che il valore restituito sia di tipo bool. Analogamente, il ConvertBack metodo presuppone che l'argomento value sia di tipo bool e che il valore restituito sia int. In caso contrario, si verificherà un'eccezione di runtime.
È possibile scrivere convertitori di valori per essere più generalizzati e accettare diversi tipi di dati. I metodi Convert e ConvertBack possono usare gli operatori as o is con il parametro value, oppure possono chiamare GetType su tale parametro per determinarne il tipo e quindi eseguire l'operazione appropriata. Il tipo previsto del valore restituito di ogni metodo viene assegnato dal targetType parametro . In alcuni casi, i convertitori di valori vengono usati con data binding di tipi di destinazione diversi. In questo caso il convertitore di valori può usare l'argomento targetType per eseguire una conversione per il tipo corretto.
Se la conversione eseguita è diversa per impostazioni locali diverse, usare il parametro culture per questo scopo.
Proprietà del convertitore di binding
Le classi del convertitore di valori possono avere proprietà e parametri generici. Il convertitore di valori seguente converte un oggetto bool dall'origine a un oggetto di tipo T per la destinazione:
public class BoolToObjectConverter<T> : IValueConverter
{
public T TrueObject { get; set; }
public T FalseObject { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (bool)value ? TrueObject : FalseObject;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((T)value).Equals(TrueObject);
}
}
Nell'esempio seguente viene illustrato come usare questo convertitore per visualizzare il valore di una Switch visualizzazione. Anche se è comune instanziare i convertitori di valori come risorse in un dizionario di risorse, questo esempio dimostra un'alternativa. In questo caso, ogni convertitore di valori viene istanziato tra i tag dell'elemento proprietà Binding.Converter.
x:TypeArguments indica l'argomento generico, e sia TrueObject che FalseObject sono entrambi impostati su oggetti di quel tipo:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.SwitchIndicatorsPage"
Title="Switch Indicators">
<ContentPage.Resources>
<Style TargetType="Label">
<Setter Property="FontSize" Value="18" />
<Setter Property="VerticalOptions" Value="Center" />
</Style>
<Style TargetType="Switch">
<Setter Property="VerticalOptions" Value="Center" />
</Style>
</ContentPage.Resources>
<StackLayout Padding="10, 0">
<StackLayout Orientation="Horizontal"
VerticalOptions="Center">
<Label Text="Subscribe?" />
<Switch x:Name="switch1" />
<Label>
<Label.Text>
<Binding x:DataType="Switch"
Source="{x:Reference switch1}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="x:String"
TrueObject="Of course!"
FalseObject="No way!" />
</Binding.Converter>
</Binding>
</Label.Text>
</Label>
</StackLayout>
<StackLayout Orientation="Horizontal"
VerticalOptions="Center">
<Label Text="Allow popups?" />
<Switch x:Name="switch2" />
<Label>
<Label.Text>
<Binding x:DataType="Switch"
Source="{x:Reference switch2}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="x:String"
TrueObject="Yes"
FalseObject="No" />
</Binding.Converter>
</Binding>
</Label.Text>
<Label.TextColor>
<Binding x:DataType="Switch"
Source="{x:Reference switch2}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="Color"
TrueObject="Green"
FalseObject="Red" />
</Binding.Converter>
</Binding>
</Label.TextColor>
</Label>
</StackLayout>
<StackLayout Orientation="Horizontal"
VerticalOptions="Center">
<Label Text="Learn more?" />
<Switch x:Name="switch3" />
<Label FontSize="18"
VerticalOptions="Center">
<Label.Style>
<Binding x:DataType="Switch"
Source="{x:Reference switch3}"
Path="IsToggled">
<Binding.Converter>
<local:BoolToObjectConverter x:TypeArguments="Style">
<local:BoolToObjectConverter.TrueObject>
<Style TargetType="Label">
<Setter Property="Text" Value="Indubitably!" />
<Setter Property="FontAttributes" Value="Italic, Bold" />
<Setter Property="TextColor" Value="Green" />
</Style>
</local:BoolToObjectConverter.TrueObject>
<local:BoolToObjectConverter.FalseObject>
<Style TargetType="Label">
<Setter Property="Text" Value="Maybe later" />
<Setter Property="FontAttributes" Value="None" />
<Setter Property="TextColor" Value="Red" />
</Style>
</local:BoolToObjectConverter.FalseObject>
</local:BoolToObjectConverter>
</Binding.Converter>
</Binding>
</Label.Style>
</Label>
</StackLayout>
</StackLayout>
</ContentPage>
In questo esempio, nell'ultima delle tre coppie di Switch e Label, l'argomento generico è impostato su Style, e interi oggetti Style sono forniti per i valori di TrueObject e FalseObject. Queste proprietà eseguono l'override dello stile implicito impostato nel dizionario delle risorse per Label, quindi vengono assegnate esplicitamente all'elemento Label. Attivando o disattivando il Switch si fa sì che il corrispondente Label rifletta la modifica:
Annotazioni
È anche possibile usare i trigger per implementare le modifiche nell'interfaccia utente in base ad altre visualizzazioni. Per altre informazioni, vedere Trigger.
Parametri del convertitore di associazioni
La Binding classe definisce una ConverterParameter proprietà e l'estensione Binding di markup definisce anche una ConverterParameter proprietà . Se questa proprietà è impostata, il valore viene passato ai metodi Convert e ConvertBack come argomento parameter. Anche se l'istanza del convertitore di valori viene condivisa tra più data binding, può ConverterParameter essere diversa per eseguire conversioni diverse.
L'uso della ConverterParameter proprietà può essere illustrato con un programma di selezione colori. Nell'esempio seguente viene illustrato RgbColorViewModel, che ha tre proprietà di tipo float denominate Red, Green e Blue che usa per costruire un valore Color:
public class RgbColorViewModel : INotifyPropertyChanged
{
Color color;
string name;
public event PropertyChangedEventHandler PropertyChanged;
public float Red
{
get { return color.Red; }
set
{
if (color.Red != value)
{
Color = new Color(value, color.Green, color.Blue);
}
}
}
public float Green
{
get { return color.Green; }
set
{
if (color.Green != value)
{
Color = new Color(color.Red, value, color.Blue);
}
}
}
public float Blue
{
get { return color.Blue; }
set
{
if (color.Blue != value)
{
Color = new Color(color.Red, color.Green, value);
}
}
}
public Color Color
{
get { return color; }
set
{
if (color != value)
{
color = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Red"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Green"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Blue"));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));
Name = NamedColor.GetNearestColorName(color);
}
}
}
public string Name
{
get { return name; }
private set
{
if (name != value)
{
name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
I valori delle Redproprietà , Greene Blue possono essere compresi tra 0 e 1. Tuttavia, è possibile preferire che i componenti vengano visualizzati come valori esadecimali a due cifre. Per visualizzarli come valori esadecimali in XAML, devono essere moltiplicati per 255, convertiti in un numero intero e quindi formattati con una specifica "X2" nella StringFormat proprietà . La moltiplicazione per 255 e la conversione in un numero intero può essere eseguita dal convertitore di valori. Per rendere il convertitore di valori il più generalizzato possibile, il fattore di moltiplicazione può essere specificato con la ConverterParameter proprietà , il che significa che immette i Convert metodi e ConvertBack come parameter argomento:
public class FloatToIntConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)Math.Round((float)value * GetParameter(parameter));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return (int)value / GetParameter(parameter);
}
double GetParameter(object parameter)
{
if (parameter is float)
return (float)parameter;
else if (parameter is int)
return (int)parameter;
else if (parameter is string)
return float.Parse((string)parameter);
return 1;
}
}
In questo esempio, il metodo Convert converte da float a int moltiplicando per il valore parameter. Il ConvertBack metodo divide l'argomento integer value per parameter e restituisce un float risultato.
Il tipo dell'argomento parameter è probabilmente diverso a seconda che il data binding sia definito in XAML o nel codice. Se la ConverterParameter proprietà di Binding è impostata nel codice, è probabile che sia impostata su un valore numerico:
binding.ConverterParameter = 255;
La ConverterParameter proprietà è di tipo Object, quindi il compilatore C# interpreta il valore letterale 255 come integer e imposta la proprietà su tale valore.
Tuttavia, in XAML ConverterParameter è probabile che sia impostato come segue:
<Label Text="{Binding Red,
Converter={StaticResource doubleToInt},
ConverterParameter=255,
StringFormat='Red = {0:X2}'}" />
Anche se 255 ha un aspetto simile a un numero, poiché ConverterParameter è di tipo Object, il parser XAML considera 255 come stringa. Per questo motivo il convertitore di valori include un metodo separato GetParameter che gestisce i casi in cui parameter sia di tipo float, int, o string.
L'esempio XAML seguente crea un'istanza di FloatToIntConverter nel proprio dizionario delle risorse.
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.RgbColorSelectorPage"
Title="RGB Color Selector"
x:DataType="local:RgbColorViewModel">
<ContentPage.BindingContext>
<local:RgbColorViewModel Color="Gray" />
</ContentPage.BindingContext>
<ContentPage.Resources>
<Style TargetType="Slider">
<Setter Property="VerticalOptions" Value="Center" />
</Style>
<Style TargetType="Label">
<Setter Property="HorizontalTextAlignment" Value="Center" />
</Style>
<local:FloatToIntConverter x:Key="floatToInt" />
</ContentPage.Resources>
<StackLayout Margin="20">
<BoxView Color="{Binding Color}"
HeightRequest="100"
WidthRequest="100"
HorizontalOptions="Center" />
<StackLayout Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Red}" />
<Label Text="{Binding Red,
Converter={StaticResource floatToInt},
ConverterParameter=255,
StringFormat='Red = {0:X2}'}" />
<Slider Value="{Binding Green}" />
<Label Text="{Binding Green,
Converter={StaticResource floatToInt},
ConverterParameter=255,
StringFormat='Green = {0:X2}'}" />
<Slider Value="{Binding Blue}" />
<Label>
<Label.Text>
<Binding Path="Blue"
StringFormat="Blue = {0:X2}"
Converter="{StaticResource floatToInt}">
<Binding.ConverterParameter>
<x:Single>255</x:Single>
</Binding.ConverterParameter>
</Binding>
</Label.Text>
</Label>
</StackLayout>
</StackLayout>
</ContentPage>
I valori delle Red proprietà e Green vengono visualizzati con un'estensione Binding di markup. La Blue proprietà, tuttavia, instanzia la classe Binding per mostrare come impostare un valore esplicito float sulla proprietà ConverterParameter.
Sfoglia l'esempio