4

Given this class:

namespace My.App.Converters
{
  [ValueConversion(typeof(bool?), typeof(Visibility))]
  public class NullableBooleanToVisibilityConverter : IValueConverter
  {
    ...
  }
}

Why do I have to do the following:

<UserControl ...
             xmlns:converters="clr-namespace:My.App.Converters">
  <UserControl.Resources>
    <converters:NullableBooleanToVisibilityConverter x:Key="visibilityConverter" />
  </UserControl.Resources>
  ...
  <Button MinWidth="120" HorizontalAlignment="Left"
          Visibility="{Binding BackButtonVisible, Converter={StaticResource visibilityConverter}}" />
  ...
</UserControl>

instead of being able to do something like the following:

<UserControl ...
             xmlns:converters="clr-namespace:My.App.Converters">
  ...
  <Button MinWidth="120" HorizontalAlignment="Left"
          Visibility="{Binding BackButtonVisible, ConverterType={x:Type converters:NullableBooleanToVisibilityConverter}}" />
  ...
</UserControl>

given that I only ever want to use this particular converter in a single place in my app, i.e. this particular UserControl?

Is the answer as simple as "Microsoft didn't feel like adding a ConverterType and you can do it yourself with markup extensions if you really want", or is there a reason of good programming style for doing it this way? ("Reusability" doesn't count for this example.)

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138

4 Answers4

3

The problem is that you are not getting an instance of your converter. To solve the same just add a static instance of your converter to your NullableBooleanToVisibilityConverter class, like this

namespace My.App.Converters
{
  [ValueConversion(typeof(bool?), typeof(Visibility))]
  public class NullableBooleanToVisibilityConverter : IValueConverter
  {
    public static NullableBooleanToVisibilityConverter Instance = new NullableBooleanToVisibilityConverter();

   /* Convert and ConvertBack methods */
  }
}

EDIT

I forgot to mention that in the binding also you have to access the static Instance

<Button MinWidth="120" HorizontalAlignment="Left"
          Visibility="{Binding BackButtonVisible, Converter={x:Static:NullableBooleanToVisibilityConverter.Instance}}" />
Mayur Dhingra
  • 1,527
  • 10
  • 27
  • this won't help the OP, as this static property named "Instance" is not automatically used. You had to assign the "Instance" to the binding, e.g. by using the {x:Static}-extension. But would this be any benefit over using a StaticResource? (except for the support of a non-default constructor) – eFloh Feb 07 '14 at 08:25
  • @eFloh Yes, I forgot to mention that you we need to use this Instance in binding. Please see my updated code. Also adding to your question - The benefit of this Instance is that we don't have to define this static resource in every page. – Mayur Dhingra Feb 07 '14 at 09:25
1

You cannot provide just the type because your converter may not have a default parameterless constructor. Therefore, a dynamic instance of the converter cannot be magicked out of thin air with just the type.

The idiom you want to use introduces a problem of creating a new convert every time the binding updates - this is bad practice from a performance point of view. You can prevent that by caching the converter but now there are even more issues;

  • when should the cache be refreshed (generate a new converter)?
  • when should the cache be disposed?
  • how do i change parameters on my converter and ensure that they won't be lost later when the cache refreshes?
Gusdor
  • 14,001
  • 2
  • 52
  • 64
  • why do you assume there is no public ctor()? – eFloh Feb 05 '14 at 13:10
  • @eFloh "**may not** have a default parameterless constructor". There are no guarantees that activator will succeed to create the instance. This makes the pattern significantly less useful than explicit resource creation and the associated benefits. – Gusdor Feb 05 '14 at 13:29
  • Oh, sorry, I overread the 'may'. and how would a static resource declaration use a non-default ctor? I assume you could declare the resource in code, but normally that wouldn't be my favorite... – eFloh Feb 07 '14 at 08:26
  • @eFloh http://stackoverflow.com/questions/1083159/calling-a-parametrized-constructor-from-xaml In .net 3.5, you would have to set properties separately. – Gusdor Feb 07 '14 at 08:30
0
ConverterType={x:Type converters:NullableBooleanToVisibilityConverter}

Do this has the instance of your Converter? Though your thought was good but by giving the Type Binding will not take the instance of that converter..

Sankarann
  • 2,625
  • 4
  • 22
  • 59
0

By using an instance of the converter, you may use a converter with properties set to specific values, consider this (theoretical) example:

<UserControl ...
             xmlns:converters="clr-namespace:My.App.Converters">
  <UserControl.Resources>
    <converters:NullableBooleanToVisibilityConverter x:Key="visibilityConverter"
                                                     IsInverted="True" />
  </UserControl.Resources>
  ...
  <Button MinWidth="120" HorizontalAlignment="Left"
          Visibility="{Binding BackButtonVisible, Converter={StaticResource visibilityConverter}}" />
  ...
</UserControl>

if you absolutely don't want to use a resource, you may declare the instance inline:

<UserControl ...
             xmlns:converters="clr-namespace:My.App.Converters">
  ...
  <Button MinWidth="120" HorizontalAlignment="Left"
          Visibility="{Binding BackButtonVisible, Converter={StaticResource visibilityConverter}}" />
    <Button.Visiblity>
      <Binding Path="BackButtonVisible">
        <Binding.Converter>
          <converters:NullableBooleanToVisibilityConverter x:Key="visibilityConverter" />
        </Binding.Converter>
      </Binding>
    </Button>
  ...
</UserControl>
eFloh
  • 2,098
  • 20
  • 24