5

I have the following converter

  [ValueConversion(typeof(bool), typeof(Visibility))]
public sealed class BoolToVisibilityConverter : IValueConverter
{
    public Visibility TrueValue { get; set; }
    public Visibility FalseValue { get; set; }

    public BoolToVisibilityConverter()
    {
        // set defaults
        TrueValue = Visibility.Visible;
        FalseValue = Visibility.Collapsed;
    }

    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        if (!(value is bool))
            return null;
        return (bool)value ? TrueValue : FalseValue;
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        if (Equals(value, TrueValue))
            return true;
        if (Equals(value, FalseValue))
            return false;
        return null;
    }
}
<conv:BoolConverter x:Key="enableStyleConvertor" TrueValue="Visible" FalseValue="Collapsed" />

Is there a way to make it more generic, ie it can return any type of object?

H.B.
  • 166,899
  • 29
  • 327
  • 400
Marcom
  • 4,621
  • 8
  • 54
  • 78
  • Just to make sure: You do know that [System.Windows.Controls.BooleanToVisibilityConverter](http://msdn.microsoft.com/en-us/library/system.windows.controls.booleantovisibilityconverter.aspx) already exists? – Heinzi Apr 11 '11 at 15:55
  • yes, this is just an old snippet to explain my point – Marcom Apr 11 '11 at 15:59
  • You might like to check out my recent post on this very subject: http://kentb.blogspot.com/2011/02/booleantovisibilityconverter.html – Kent Boogaart Apr 11 '11 at 17:28

2 Answers2

3

You just make TrueValue and FalseValue of type Object. You may want to update the Equals code to see if the objects implement IComparable as well though.

[ValueConversion(typeof(bool), typeof(object))]
public sealed class MyConverter : IValueConverter
{
    public object TrueValue { get; set; }
    public object FalseValue { get; set; }

    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        if (!(value is bool))
            return null;
        return (bool)value ? TrueValue : FalseValue;
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        if (IsEqual(value, TrueValue))
            return true;
        if (IsEqual(value, FalseValue))
            return false;
        return null;
    }

    private static bool IsEqual(object x, object y) {
        if (Equals(x, y))
          return true;

        IComparable c = x as IComparable;
        if (c != null)
           return (c.CompareTo(y) == 0);

        return false;
    }
}

To use this you'd need to explicitly define the values now though:

<local:MyConverter>
    <local:MyConverter.TrueValue>
        <Visibility>Visible</Visibility>
    </local:MyConverter.TrueValue>
    <local:MyConverter.FalseValue>
        <Visibility>Collapsed</Visibility>
    </local:MyConverter.FalseValue>
</local:MyConverter>

EDIT:

A generic version would look like this:

[ValueConversion(typeof(bool), typeof(object))]
public sealed class MyConverter<T> : IValueConverter {
    public T TrueValue { get; set; }
    public T FalseValue { get; set; }

    public object Convert(object value, Type targetType,
        object parameter, CultureInfo culture) {
        if (!(value is bool))
            return null;
        return (bool)value ? TrueValue : FalseValue;
    }

    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture) {
        if (IsEqual(value, TrueValue))
            return true;
        if (IsEqual(value, FalseValue))
            return false;
        return null;
    }

    private static bool IsEqual(object x, object y) {
        if (Equals(x, y))
            return true;

        IComparable c = x as IComparable;
        if (c != null)
            return (c.CompareTo(y) == 0);

        return false;
    }
}

This isn't easily accessible from XAML though. XAML 2009 has some additional support for generics, but that is mostly for loose XAML files (i.e. not compiled).

CodeNaked
  • 40,753
  • 6
  • 122
  • 148
  • If they are of type object, how will XAML know that `TrueValue="Visible"` needs to be converted into `myBoolConverter.TrueValue = System.Windows.Visibility.Visible` instead of, for example, the string "Visible"? – Heinzi Apr 11 '11 at 15:57
  • @Heinzi - Yes, that is one thing you give up. You'd have to explicitly define the values. I'll update my answer. – CodeNaked Apr 11 '11 at 16:00
  • is there a way to create that method as a generic class with type T ? – Marcom Apr 12 '11 at 08:59
  • @Marcom - You could make the above generic, but that makes using it in XAML harder. See [this question](http://stackoverflow.com/questions/185349/can-i-specify-a-generic-type-in-xaml) for more about creating generic classes in XAML. Alternatively, you could create concrete classes based on the generic version, to make using via XAML easier. – CodeNaked Apr 12 '11 at 11:36
  • @Marcom - Based on [this](http://blogs.windowsclient.net/rob_relyea/archive/2009/06/01/xaml-using-generic-types-in-xaml-2009.aspx) it looks like in .NET 4, it is easier to use generic types from XAML. I'll try to whip something later. – CodeNaked Apr 12 '11 at 11:38
  • @Marcom - I updated my answer with a generic version, but it looks like the generic support in XAML 2009 is only for loose XAML files. So it is still not easily to reference a generic converter from XAML. – CodeNaked Apr 18 '11 at 11:36
1

I would simply use two classes,

BooleanToVisibilityConverter (Visible on true)
OppositeBooleanToVisibilityConverter (Visible on false)

Or I will pass a converter parameter called "inverse"

<Button 
   Visibility="{Binding myValue, 
      Converter={StaticResource booleanToVisibility},
      ConverterParameter=inverse}" />

You can then check inverse being passed in ConverterParameter and return Visible on false.

You can pass anything on ConverterParameter or it can also be bound to something that can control your logic.

Akash Kava
  • 39,066
  • 20
  • 121
  • 167