WPF combo box change sort order for items

Hi,
   I have created a very simple example to show my problem. I am binding a combo box from a datatable that pulls from my enum in Product class. There is a convertor class that just converts enum to a datatable. My problem is that I want the order of Products to be different then what the enum gives back. I have been looking for a similar example to rearrange the collections items but have not found something similar since I dont want to just sort them alphabetically. I read that a collections IComparer property can allow this? I also wanted to accomplish this in code behind and do NOT want to rearrange the enum. I am including my simple example in the attached files, please give the example in code. Here is the default order from enum, thanks in advance :
 
 Bread ,
 Apple ,
 Milk ,
 Juice ,
 Grapes ,
 Cereal

Here is the order I want to display the items in the combo box:

Milk,
Juice.
Cereal,
Bread,
Apple,
Grapes
Window1xaml.txt
Window1cs.txt
Product.txt
groovbox303Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

mikebirtCommented:
Hi,

whilst you could use an IComparer you still need something for it to work on, unless you're suggesting hard coding that order in the IComparer implementation? Can i suggest using some attribute to specify order on your enum fields upon which your IComparer implementation can use?

In the code sample below i've provided the enum you've specified with an order attribute which allows you to declare the order you want. I've provided the attribute, an extension method to get the order number value and an IComparer implementation for the enum type.

HTH

Mike

    public enum FoodType
    {
        [FoodOrderAttribute(4)]
        Bread,

        [FoodOrderAttribute(5)]
        Apple,

        [FoodOrderAttribute(1)]
        Milk,

        [FoodOrderAttribute(2)]
        Juice,

        [FoodOrderAttribute(6)]
        Grapes,

        [FoodOrderAttribute(3)]
        Cereal
    }

    [AttributeUsage(AttributeTargets.Field,AllowMultiple=false)]
    public class FoodOrderAttribute : Attribute
    {
        public FoodOrderAttribute(int orderNumber)
        {
            OrderNumber = orderNumber;
        }

        public int OrderNumber { get; private set; }
    }

    public static class FoodTypeExtension
    {
        public static int GetOrderNumber(this FoodType foodField)
        {
            object[] attribs = typeof(FoodType).GetField(foodField.ToString()).GetCustomAttributes(typeof(FoodOrderAttribute), true);

            if (attribs != null &&
                attribs.Length == 1)
            {
                return ((FoodOrderAttribute)attribs[0]).OrderNumber;
            }

            return int.MinValue;
        }
    }

    public class FoodComparer : IComparer<FoodType>
    {
        #region IComparer<FoodType> Members

        public int Compare(FoodType x, FoodType y)
        {
            return Comparer.Default.Compare(x.GetOrderNumber(), y.GetOrderNumber());
         }
        #endregion
    }

Open in new window

0
mikebirtCommented:
Hi,

sorry, i missed off the illustration of my previous code in action...

So, implement a data provider; create a list, populate it with the items in your enum, apply the IComparer and apply to the ItemsSource. You can link your sorting code to your item source in xaml - i'm sure there are countless otherways also, but this is fairly neat. The drop down is then ordered according to the FoodOrderAttributes.

I'm not saying this is the approach you should take with your Xaml, simply using it as a quick illustration of the code example in action - i should have included this in my previous post to make it a more complete example

HTH

Mike
// first a basic data provider example

    public class FoodProvider
    {
        List<FoodType> data = null;

        public FoodType[] OrderedFood
        {
            get
            {
                if (data == null)
                {
                    data = new List<FoodType>();

                    foreach (FoodType ft in System.Enum.GetValues(typeof(FoodType)))
                    {
                        data.Add(ft);
                    }

                    data.Sort(new FoodComparer());
                }

                return data.ToArray();
            }
        }
    }

// next a brief Xaml illustration
<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="Window1" Height="300" Width="300">

    <Window.Resources>
        <local:FoodProvider x:Key="foodProvider" />
    </Window.Resources>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <ComboBox Grid.Column="1" x:Name="combo" ItemsSource="{Binding Source={StaticResource foodProvider}, Path=OrderedFood}" />
    </Grid>
</Window>

Open in new window

0
groovbox303Author Commented:
Hi mikebrit, thanks for your reply. Im sure your solution would work but the prob is I can not modify the enum or add attributes to it. let me put it another way, say we only had to move just the item Bread at the bottom of the list so the rest of the list would remain same, so what if I wanted the list to be
 
 Apple ,
 Milk ,
 Juice ,
 Grapes ,
 Cereal,
 Bread

 so the only diff would be moving Bread to the bottom of the list, sorry my experience with the Icomparable, Icomparer interfaces is rather limited. So what if only this is the requirement without modifying the enum and possibly doing this in window1.cs
0
mikebirtCommented:
Hi,

In this case you need to introduce some other element to contain the ordering you need. Maybe, you could simply hard code this order in the IComparer i supplied - or have it configurable but used by the IComparer. The solution is the same, but rather than use the attributes, load the order into the IComparer class and resolve it that way.

i've given a hard coded example of how you could achieve this. Ideally this order would be externalised, however at least this way it's located clearly and easily changable.

HTH

Mike
    public class FoodComparer : IComparer<FoodType>
    {
        private static Dictionary<FoodType, int> foodOrders;

        static FoodComparer()
        {
            foodOrders = new Dictionary<FoodType, int>();
            foodOrders.Add(FoodType.Bread, 6);
            foodOrders.Add(FoodType.Apple, 1);
            foodOrders.Add(FoodType.Milk, 2);
            foodOrders.Add(FoodType.Juice, 3);
            foodOrders.Add(FoodType.Grapes, 4);
            foodOrders.Add(FoodType.Cereal, 5);
        }

        #region IComparer<FoodType> Members

        public int Compare(FoodType x, FoodType y)
        {
            return Comparer.Default.Compare(foodOrders[x], foodOrders[y]);
        }
        #endregion
    }

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.