wpf
Convertidores de Valor y Multivalor
Buscar..
Parámetros
Parámetro | Detalles |
---|---|
valor | El valor producido por la fuente de enlace. |
valores | La matriz de valores, producida por la fuente de enlace. |
tipo de objetivo | El tipo de la propiedad objetivo de enlace. |
parámetro | El parámetro convertidor a utilizar. |
cultura | La cultura a utilizar en el convertidor. |
Observaciones
Qué son IValueConverter e IMultiValueConverter
IValueConverter e IMultiValueConverter: interfaces que proporcionan una manera de aplicar una lógica personalizada a un enlace.
Para que sirven
- Tiene algún valor de tipo pero desea mostrar valores cero de una manera y números positivos de otra manera
- Tiene algún valor de tipo y desea mostrar el elemento en un caso y ocultarse en otro
- Tienes un valor numérico de dinero pero quieres mostrarlo como palabras
- Tiene un valor numérico pero desea mostrar imágenes diferentes para números diferentes
Estos son algunos de los casos simples, pero hay muchos más.
Para casos como este, puede usar un convertidor de valores. Estas clases pequeñas, que implementan la interfaz IValueConverter o IMultiValueConverter, actuarán como intermediarios y traducirán un valor entre la fuente y el destino. Por lo tanto, en cualquier situación en la que necesite transformar un valor antes de que llegue a su destino o vuelva a su origen, es probable que necesite un convertidor.
Construido en BooleanToVisibilityConverter [IValueConverter]
Convertidor entre booleanos y visibilidad. Obtener valor bool
en la entrada y devuelve el valor de Visibility
.
NOTA: Este convertidor ya existe en el espacio de nombres System.Windows.Controls
.
public sealed class BooleanToVisibilityConverter : IValueConverter
{
/// <summary>
/// Convert bool or Nullable bool to Visibility
/// </summary>
/// <param name="value">bool or Nullable bool</param>
/// <param name="targetType">Visibility</param>
/// <param name="parameter">null</param>
/// <param name="culture">null</param>
/// <returns>Visible or Collapsed</returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool bValue = false;
if (value is bool)
{
bValue = (bool)value;
}
else if (value is Nullable<bool>)
{
Nullable<bool> tmp = (Nullable<bool>)value;
bValue = tmp.HasValue ? tmp.Value : false;
}
return (bValue) ? Visibility.Visible : Visibility.Collapsed;
}
/// <summary>
/// Convert Visibility to boolean
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns></returns>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Visibility)
{
return (Visibility)value == Visibility.Visible;
}
else
{
return false;
}
}
}
Usando el convertidor
- Definir recurso
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
- Utilízalo en encuadernación
<Button Visibility="{Binding AllowEditing,
Converter={StaticResource BooleanToVisibilityConverter}}"/>
Convertidor con propiedad [IValueConverter]
Muestre cómo crear un convertidor simple con parámetro a través de la propiedad y luego páselo en la declaración. Convertir el valor bool
a la Visibility
. Permite invertir el valor del resultado estableciendo la propiedad Inverted
en True
.
public class BooleanToVisibilityConverter : IValueConverter
{
public bool Inverted { get; set; }
/// <summary>
/// Convert bool or Nullable bool to Visibility
/// </summary>
/// <param name="value">bool or Nullable bool</param>
/// <param name="targetType">Visibility</param>
/// <param name="parameter">null</param>
/// <param name="culture">null</param>
/// <returns>Visible or Collapsed</returns>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool bValue = false;
if (value is bool)
{
bValue = (bool)value;
}
else if (value is Nullable<bool>)
{
Nullable<bool> tmp = (Nullable<bool>)value;
bValue = tmp ?? false;
}
if (Inverted)
bValue = !bValue;
return (bValue) ? Visibility.Visible : Visibility.Collapsed;
}
/// <summary>
/// Convert Visibility to boolean
/// </summary>
/// <param name="value"></param>
/// <param name="targetType"></param>
/// <param name="parameter"></param>
/// <param name="culture"></param>
/// <returns>True or False</returns>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Visibility)
{
return ((Visibility) value == Visibility.Visible) && !Inverted;
}
return false;
}
}
Usando el convertidor
- Definir espacio de nombres
xmlns:converters="clr-namespace:MyProject.Converters;assembly=MyProject"
- Definir recurso
<converters:BooleanToVisibilityConverter x:Key="BoolToVisibilityInvertedConverter"
Inverted="False"/>
- Utilízalo en encuadernación
<Button Visibility="{Binding AllowEditing, Converter={StaticResource BoolToVisibilityConverter}}"/>
Convertidor simple de agregar [IMultiValueConverter]
Muestre cómo crear un simple convertidor de IMultiValueConverter
y use MultiBinding
en xaml. Obtener la suma de todos los valores pasados por la matriz de values
.
public class AddConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
decimal sum = 0M;
foreach (string value in values)
{
decimal parseResult;
if (decimal.TryParse(value, out parseResult))
{
sum += parseResult;
}
}
return sum.ToString(culture);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
Usando el convertidor
- Definir espacio de nombres
xmlns:converters="clr-namespace:MyProject.Converters;assembly=MyProject"
- Definir recurso
<converters:AddConverter x:Key="AddConverter"/>
- Utilízalo en encuadernación
<StackPanel Orientation="Vertical">
<TextBox x:Name="TextBox" />
<TextBox x:Name="TextBox1" />
<TextBlock >
<TextBlock.Text>
<MultiBinding Converter="{StaticResource AddConverter}">
<Binding Path="Text" ElementName="TextBox"/>
<Binding Path="Text" ElementName="TextBox1"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
Convertidores de uso con ConverterParameter
Muestre cómo crear un convertidor simple y use ConverterParameter
para pasar el parámetro al convertidor. Multiplique el valor por el coeficiente pasado en ConverterParameter.
public class MultiplyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return 0;
if (parameter == null)
parameter = 1;
double number;
double coefficient;
if (double.TryParse(value.ToString(), out number) && double.TryParse(parameter.ToString(), out coefficient))
{
return number * coefficient;
}
return 0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
Usando el convertidor
- Definir espacio de nombres
xmlns:converters="clr-namespace:MyProject.Converters;assembly=MyProject"
- Definir recurso
<converters:MultiplyConverter x:Key="MultiplyConverter"/>
- Utilízalo en encuadernación
<StackPanel Orientation="Vertical">
<TextBox x:Name="TextBox" />
<TextBlock Text="{Binding Path=Text,
ElementName=TextBox,
Converter={StaticResource MultiplyConverter},
ConverterParameter=10}"/>
</StackPanel>
Grupo de convertidores multiples [IValueConverter]
Este convertidor encadenará varios convertidores juntos.
public class ValueConverterGroup : List<IValueConverter>, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return this.Aggregate(value, (current, converter) => converter.Convert(current, targetType, parameter, culture));
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
En este ejemplo, el resultado booleano de EnumToBooleanConverter
se usa como entrada en BooleanToVisibilityConverter
.
<local:ValueConverterGroup x:Key="EnumToVisibilityConverter">
<local:EnumToBooleanConverter/>
<local:BooleanToVisibilityConverter/>
</local:ValueConverterGroup>
El botón solo estará visible cuando la propiedad CurrentMode
esté configurada en Ready
.
<Button Content="Ok" Visibility="{Binding Path=CurrentMode, Converter={StaticResource EnumToVisibilityConverter}, ConverterParameter={x:Static local:Mode.Ready}"/>
Uso de MarkupExtension con convertidores para omitir la declaración de recurso
Normalmente para usar el convertidor, tenemos que definirlo como recurso de la siguiente manera:
<converters:SomeConverter x:Key="SomeConverter"/>
Es posible omitir este paso definiendo un convertidor como MarkupExtension
e implementando el método ProvideValue
. El siguiente ejemplo convierte un valor a su negativo:
namespace MyProject.Converters
{
public class Converter_Negative : MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return this.ReturnNegative(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return this.ReturnNegative(value);
}
private object ReturnNegative(object value)
{
object result = null;
var @switch = new Dictionary<Type, Action> {
{ typeof(bool), () => result=!(bool)value },
{ typeof(byte), () => result=-1*(byte)value },
{ typeof(short), () => result=-1*(short)value },
{ typeof(int), () => result=-1*(int)value },
{ typeof(long), () => result=-1*(long)value },
{ typeof(float), () => result=-1f*(float)value },
{ typeof(double), () => result=-1d*(double)value },
{ typeof(decimal), () => result=-1m*(decimal)value }
};
@switch[value.GetType()]();
if (result == null) throw new NotImplementedException();
return result;
}
public Converter_Negative()
: base()
{
}
private static Converter_Negative _converter = null;
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (_converter == null) _converter = new Converter_Negative();
return _converter;
}
}
}
Usando el convertidor:
Definir espacio de nombres
xmlns: converters = "clr-namespace: MyProject.Converters; assembly = MyProject"
Ejemplo de uso de este convertidor en enlace
<RichTextBox IsReadOnly="{Binding Path=IsChecked, ElementName=toggleIsEnabled, Converter={converters:Converter_Negative}}"/>
Use IMultiValueConverter para pasar múltiples parámetros a un comando
Es posible pasar varios valores enlazados como un CommandParameter
utilizando MultiBinding
con un IMultiValueConverter
muy simple:
namespace MyProject.Converters
{
public class Converter_MultipleCommandParameters : MarkupExtension, IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return values.ToArray();
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
private static Converter_MultipleCommandParameters _converter = null;
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (_converter == null) _converter = new Converter_MultipleCommandParameters();
return _converter;
}
public Converter_MultipleCommandParameters()
: base()
{
}
}
}
Usando el convertidor:
Ejemplo de implementación: método llamado cuando se ejecuta
SomeCommand
( nota:DelegateCommand
es una implementación deICommand
que no se proporciona en este ejemplo ):private ICommand _SomeCommand; public ICommand SomeCommand { get { return _SomeCommand ?? (_SomeCommand = new DelegateCommand(a => OnSomeCommand(a))); } } private void OnSomeCommand(object item) { object[] parameters = item as object[]; MessageBox.Show( string.Format("Execute command: {0}\nParameter 1: {1}\nParamter 2: {2}\nParamter 3: {3}", "SomeCommand", parameters[0], parameters[1], parameters[2])); }
Definir espacio de nombres
xmlns: converters = "clr-namespace: MyProject.Converters; assembly = MyProject"
Ejemplo de uso de este convertidor en enlace
<Button Width="150" Height="23" Content="Execute some command" Name="btnTestSomeCommand" Command="{Binding Path=SomeCommand}" > <Button.CommandParameter> <MultiBinding Converter="{converters:Converter_MultipleCommandParameters}"> <Binding RelativeSource="{RelativeSource Self}" Path="IsFocused"/> <Binding RelativeSource="{RelativeSource Self}" Path="Name"/> <Binding RelativeSource="{RelativeSource Self}" Path="ActualWidth"/> </MultiBinding> </Button.CommandParameter> </Button>