views:

1777

answers:

1

Hi,

I just started playing around with Silverlight and a supposedly simple thing like binding a Combobox is driving me nuts. I read a bunch of articles now but none really address the issue that I'm after or were made for Silverlight 2 and don't seem to work.

Let's say I have an entity object "User" which has a "UserStatus" field. In the database UserStatus field is defined as byte and in code it's defined as:

public enum UserStatus : byte
{
    Active = 1,
    Locked = 2,
    Suspended = 3,
}

When ADO.NET entity framework creates the user entity it leaves the UserStatus field as byte. So, to address this I stumbled across IValueConverter and implemented the following:

public class EnumConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        switch (parameter.ToString())
        {
            case "UserStatus":
                return ((UserStatus)value).ToString();;
        }

        return "?";
    }

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

    #endregion
}

Now, I also need to supply the Combobox an ItemSource, so I implemented this:

internal static class EnumValueCache
{
    private static readonly IDictionary<Type, object[]> Cache = new Dictionary<Type, object[]>();

    public static object[] GetValues(Type type)
    {
        if (!type.IsEnum)
            throw new ArgumentException("Type '" + type.Name + "' is not an enum");

        object[] values;
        if (!Cache.TryGetValue(type, out values))
        {
            values = type.GetFields()
                .Where(f => f.IsLiteral)
                .Select(f => f.GetValue(null))
                .ToArray();
            Cache[type] = values;
        }
        return values;
    }
}

public class EnumValuesConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
            return null;

        switch (parameter.ToString())
        {
            case "UserStatus":
                return EnumValueCache.GetValues(typeof(UserStatus));
        }

        return null;
    }

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

And then finally, this is how I added it to my XAML:

                            <ComboBox ItemsSource="{Binding UserStatus, Mode=TwoWay, Converter={StaticResource EnumValuesConverter}, ConverterParameter='UserStatus'}" 
                                  SelectedItem="{Binding UserStatus, Mode=TwoWay, Converter={StaticResource EnumConverter}, ConverterParameter='UserStatus'}" />

What happens now though is that the ItemsSource gets correctly bound and I see all the options in the dropdown, however, the SelectedItem is not set. Even when I try to manually set SelectedItem to ="1" or "Active", none of them work. Can anyone help me out and tell me what's wrong, why I can't seem to get the SelectedItem set?

Thanks,

Tom

+2  A: 

I can see two problems with your code.

First, in silverlight 3 the ComboBox matches the object in the SelectedItem to the set of objects in the ItemsSource via the object.Equals method. However your GetValues method returns an array of Boxed enum values. Whereas your EnumConverter returns a string. Hence you asking Silverlight to compare a byte with a string, these are never equal.

Secondly, you need to place some code in the ConvertBack method if you are going to two way bind the SelectedItem (BTW there is no need for a twoway binding the ItemsSource).

AnthonyWJones
DUH, you're quite correct of course, thanks Anthony. Simply calling f.GetValue(null).ToString() fixes it. Btw. thx I'm aware of the unimplemented ConvertBack for TwoWay binding, just wanted to get the first part of the binding correct first :)
Tom Frey