Para não terem de criar um recurso estático sempre que querem usar um conversor, podem criar conversores que são simultaneamente extensões markup.
Normalmente declaram-se os conversores da seguinte maneira:
<UserControl.Resources>
<my:BoolVisibilityConverter x:Key="visibilityConverter" />
</UserControl.Resources>
E depois chamam-se assim:
<Label
Content="Please wait!"
Visibility="{Binding IsBusy, Converter={StaticResource visibilityConverter}}" />
Não sei quanto a vocês, mas eu não retiro nenhum prazer em ter de declarar um conversor sempre que quero usar um.
Para ultrapassar esta inconveniência, podemos criar híbridos de conversores e extensões markup. Vi esta abordagem pela primeira vez no blog Dr. WPF.
Primeiro criamos uma classe template genérica que vai ser a base de todos os nossos conversores.
public abstract class ConverterMarkupExtension<T> : MarkupExtension, IValueConverter where T: class, new()
{
private static T _converter = null;
public ConverterMarkupExtension()
{
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return _converter ?? (_converter = new T());
}
public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
public abstract object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
}
Depois herdamos dessa classe ao criar um conversor:
[ValueConversion(typeof(bool), typeof(Visibility))]
public class BoolVisibilityConverter : ConverterMarkupExtension<BoolVisibilityConverter>
{
public BoolVisibilityConverter()
{
}
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && value is bool)
{
if ((bool)value)
{
return Visibility.Visible;
}
}
return Visibility.Collapsed;
}
public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Agora sempre que queremos usar o conversor não temos de o declarar explicitamente. Apenas fazemos assim:
<Label
Content="Please wait!"
Visibility="{Binding IsBusy, Converter={my:BoolVisibilityConverter}}" />
Podem-se estar a perguntar: porque é que precisamos de uma classe template genérica? Porque não remover o template e a instância singleton da classe abstracta e simplesmente fazer return this;
no método ProvideValue?
Certamente poderiam fazer assim e funcionaria correctamente como está, mas ao usar a instância singleton estão a separar a extensão markup do conversor, que têm tempos de vida diferentes.
Imaginem que no futuro as extensões markup passarão a ser disposed depois do método ProvideValue ser chamado. Nesse cenário, persistir o conversor separadamente evita o problema.