0

I have a TextBox that I want to enable if a Order's Status is either OrderStatus.New or OrderStatus.Ordered. It it's something else, the TextBox should stay disabled.

<TextBox Text="{Binding OrderedAmount}" IsEnabled="True"/>

I assume I need to use some kind of MultiBinding, but cannot seem to find a proper resource on how to do that in this particular case.

Tatu Ulmanen
  • 123,288
  • 34
  • 187
  • 185
  • Just bind `IsEnabled` to the `OrderStatus` and use a converter to return `true` or `false` depending what the enum value is. – Bob. May 01 '13 at 15:16
  • 1
    Hi, You could create a `style` that uses a `DataTrigger` which could set the `textbox` value to be enabled. Take a look at this thread; http://stackoverflow.com/questions/6211264/why-cant-i-use-a-datatrigger-to-set-textbox-isenabled-true Hope it helps! – greg May 01 '13 at 15:17

1 Answers1

6

You should use a ValueConverter for this:

public class IsNewOrOrderedConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        OrderStatus status = (OrderStatus)value;
        return status == OrderStatus.New || status == OrderStatus.Ordered;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Then use it as the converter in your xaml:

<TextBox Text="{Binding OrderedAmount}" 
          IsEnabled="{Binding OrderStatus, Converter={StaticResource IsNewOrOrderedConverter}"/>

Don't forget to declare the resource:

 <App.Resources>
    <myPrefix:IsNewOrOrderedConverter x:Key="IsNewOrOrderedConverter" />
 </App.Resources>

http://msdn.microsoft.com/en-us/library/ms750613.aspx on declaring resources.

Parametrization

A single converter can be made parametrized so it can be reused for different order types. The XAML would be like this:

        <local:OrderStatusToBooleanConverter 
               StatusList="New,Ordered"  x:Key="NewOrOrderedConverter" />
        <local:OrderStatusToBooleanConverter 
               StatusList="Delivered"  x:Key="DeliveredConverter" />

This requires some special tactics since there is no way by default to make it readable (with enum values separated by a comma). That's where we need a type converter:

public class StringToOrderStatusArrayConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        return sourceType == typeof(string);
    }
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if (value == null)
        {
            return new OrderStatus[0];
        }
        else
        {
            return (from s in value.ToString().Split(',')
                    select Enum.Parse(typeof(OrderStatus), s))
                    .OfType<OrderStatus>()
                    .ToArray<OrderStatus>();

        }
    }
}

The type converter converts the input string array of enum values separated by a comma into an array.

This array can then be fed into the ValueConverter:

public class OrderStatusToBooleanConverter : IValueConverter
{
    [TypeConverter(typeof(StringToOrderStatusArrayConverter))]
    public OrderStatus[] StatusList { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        OrderStatus status = (OrderStatus)value;
        return StatusList != null && StatusList.Contains(status);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Bas
  • 26,772
  • 8
  • 53
  • 86
  • Excellent answer! If I have an another TextBox called DeliveredAmount which is otherwise similar but should be enabled when OrderStatus is Delivered, do I need to create another Converter or can I somehow check for the field in question inside the Converter? I.e. does the Converter know which field it's converting for? – Tatu Ulmanen May 01 '13 at 16:02
  • 1
    @TatuUlmanen It would need a new converter since the convert only knows the value it is given, not what it is for, and there won't be a way to distinguish a New Order from a Delivered Order. – Bob. May 01 '13 at 17:02
  • 1
    @TatuUlmanen I have updated my answer to include working with parameters, this is a bit more complex however. – Bas May 02 '13 at 07:14