c# - stringformat - Usar convertidores de valor en WPF sin tener que definirlos primero como recursos
ivalueconverter wpf (4)
Definitivamente consideraría la sugerencia de Micah que implica el uso de una instancia de singleton estático de tu convertidor. Pero otra cosa a tener en cuenta es que si está usando un patrón de presentación separado como MVVM, a menudo puede evitar el requisito de un convertidor de valor implementando la conversión en el ViewModel.
Hay muchas razones por las que puede querer hacer esto.
Por un lado, es mucho más comprobable. Las pruebas de su unidad pueden estar seguras de que lo que esté saliendo de ViewModel es lo que mostrará la interfaz de usuario. Puede imaginar probar un requisito de que los valores en dólares deben seguir el formato de moneda de la cultura actual, se deben usar dos decimales, etc.
Otra buena razón es que las excepciones en los convertidores de valor no se tratarán como errores de validación, lo que puede ser un gran problema en Silverlight. Incluso si configura ValidatesOnExceptions como verdadero en el enlace, si su convertidor de valor arroja una excepción, Silverlight simplemente lo dejará propagar. Sin embargo, si usa ViewModel para realizar la conversión, una excepción se tratará como un error de validación.
El inconveniente es que pierde parte de la "reutilización" de un convertidor de valor de propósito general.
¿Es posible usar convertidores de valor sin tener que definirlos de antemano como recursos?
En este momento tengo
<Window.Resources>
<local:TrivialFormatter x:Key="trivialFormatter" />
</Window.Resources>
y
<Button Width="{Binding Width, ElementName=textBox1, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource trivialFormatter}}" Height="50">
¿No sería posible que en lugar de tener que declarar el recurso trivialFormatter en Window.Resources, pudiera referirlo directamente desde el enlace de ancho del botón? Algo como
Converter = {local:TrivialFormatter}
Gracias
No sé de una manera de hacer esto de la manera que estás diciendo, pero lo intenté como una muestra y funcionó. En su archivo App.xaml.cs, puede crear un método que use la reflexión para cargar los conversores.
private void Application_Startup(object sender, StartupEventArgs e)
{
LoadConverters();
}
private void LoadConverters()
{
foreach(var t in Assembly.GetExecutingAssembly().GetTypes())
{
if (t.GetInterfaces().Any(i => i.Name == "IValueConverter"))
{
Resources.Add(t.Name, Activator.CreateInstance(t));
}
}
}
Entonces puedes usar el convertidor con esto, a mitad de camino, supongo.
<Button Width="{Binding Width, Converter={StaticResource TrivialFormatter}}" />
El problema con el enfoque que está proponiendo es que el analizador Xaml no sabe cuándo y cuántas instancias de su convertidor crear. Crearlo como un recurso asegura solo una instancia.
Técnicamente creo que puedes hacer esto, pero el XAML es tan horrible que hará que el enfoque de "muchos recursos triviales" parezca un refugio de simplicidad y claridad en comparación:
<Button Height="50">
<Button.Width>
<Binding Path="Width" ElementName="textBox1" UpdateSourceTrigger="PropertyChanged">
<Binding.Converter>
<local:TrivialFormatter />
</Binding.Converter>
</Binding>
</Button.Width>
</Button>
No lo he probado porque incluso leerlo me hace agua los ojos ...
En el caso de IValueConverter
tipo IValueConverter
(p. Ej., No necesitan ningún estado de la instancia de enlace actual) utilizo conversores estáticos, es decir:
Converter={x:Static SomeNamespace:SomeConverter.Instance}
También hay una gran publicación del Dr. WPF sobre el uso de una extensión de marcado para que quede más limpio en línea aquí .