0

I'm trying to pass an Enum into a method that will create columns for a gridview. I can pass the Enum as Enum passEnum OR Type enumType, and either works, just not together. What I mean is if I pass it as a type the Enum.GetNames() method accepts it, and if I pass it as an enum, the StringEnum.GetString() method accepts it. But I can't pass one and have them both accept it and I can't pass them separately (enum and type) and have both accept it. The method that AMOST works:

public static void AddColumnsToGridView(GridView gv, Enum passEnum, Type enumType)
{
    BoundField bf = new BoundField();
    int c = 0;
    foreach (string item in Enum.GetNames(enumType))
    {
        bf = new BoundField();
        bf.HeaderText = StringEnum.GetString((passEnum)c);
        bf.DataField = item;
        bf.ItemStyle.CssClass = "siteFont leftPaddingThree";
        bf.SortExpression = item;
        gv.Columns.Add(bf);
        c++;
    }
}

I get a red squiggle line under passEnum that says: "The type or namespace 'passEnum' cannot be found... etc". For some reason I can get this to work outside of a method like this:

BoundField bf = new BoundField();
int c = 0;
foreach (string item in Enum.GetNames(typeof(PatientRX)))
{
    bf = new BoundField();
    bf.HeaderText = StringEnum.GetString((PatientRX)c);
    bf.DataField = item;
    bf.ItemStyle.CssClass = "siteFont leftPaddingThree";
    bf.SortExpression = item;
    gvRX.Columns.Add(bf);
    c++;
}

The StringEnum.GetString() method gets a string value attached to the enum. It requires an enum to be passed to it. How can I get this to work in a method?

RB.
  • 36,301
  • 12
  • 91
  • 131
Barry Franklin
  • 1,781
  • 1
  • 27
  • 45

2 Answers2

0

It looks like you're trying to write a generic method there, without actually using generics, try something like this:

public static void AddColumnsToGridView<TEnum>(GridView gv)
{
    Type enumType = typeof(TEnum);
    BoundField bf = new BoundField();
    int c = 0;
    foreach (string item in Enum.GetNames(enumType))
    {
        bf = new BoundField();
        bf.HeaderText = StringEnum.GetString((Enum)c);
        bf.DataField = item;
        bf.ItemStyle.CssClass = "siteFont leftPaddingThree";
        bf.SortExpression = item;
        gv.Columns.Add(bf);
        c++;
    }
}

It's not really how I'd go about doing it from scratch, but it should work.

edit: Sorry, I forgot to show an example of calling that, which would look like this:

AddColumnsToGridView<MyEnumType>(gridView);

edit 2: I mentioned in the comment below that you'll have problems if the enum doesn't start at 0 or misses out values. You might want to try this instead:

public static void AddColumnsToGridView(GridView gv, Type enumType)
{
    Array values = Enum.GetValues(enumType)
    string[] names= Enum.GetNames(enumType)

    BoundField bf = new BoundField();
    for (int i = 0; i < names.Length; i++)
    {
        bf = new BoundField();
        bf.HeaderText = StringEnum.GetString((Enum)values.GetValue(i));
        bf.DataField = names[i];
        bf.ItemStyle.CssClass = "siteFont leftPaddingThree";
        bf.SortExpression = names[i];
        gv.Columns.Add(bf);
    }
}

Note that this is no longer a generic method, as it doesn't need to be (It's better this way - you won't get multiple versions of the method JITted at runtime for each enum type). Just call it like this:

AddColumnsToGridView(gridView, typeof(MyEnum));

I obviously don't have the code that you have for StringEnum, so I haven't compiled this up myself, but I think it should be fine. Let me know if it's still a problem.

Mike Goatly
  • 7,380
  • 2
  • 32
  • 33
  • Thanks for the lesson in generics Mike, it is helpuful and quite useful, but there is still a probelem in the line: `bf.HeaderText = StringEnum.GetString((TEnum)c);` I get the error "Argument 1: cannot convert from 'TEnum' to 'System.Enum'" – Barry Franklin Apr 06 '11 at 11:55
  • Sorry that should have been ((Enum)c) not ((TEnum)c) - edited. One of the problems you would have faced with this approach is that an enum doesn't always have to start with 0, and it's possible it will miss values out, e.g. an enum could be defined as: public enum MyEnum { Value1 = 3, Value2 = 9 } This would break with the above code, because you're making the assumption that the enum values will start at 0 and increment one at a time. – Mike Goatly Apr 06 '11 at 12:45
  • I know about the enum values being off and that would be an issue, sure, but I wasn't going to be using enums with specified values for this, just enum lists with standard values starting at 0. – Barry Franklin Apr 06 '11 at 12:57
0

I worked around the problem by writing a new method for the StringEnum class that returns a list of string values for the enum instead of trying to pull each string indivually... like this:

       public static void AddColumnsToGridView(GridView gv, Type enumType)
       {
           gv.Columns.Clear();
           List<string> headers = StringEnum.GetStringValueList(enumType);
           BoundField bf = new BoundField();
           int c = 0;
           foreach (string item in Enum.GetNames(enumType))
           {
              bf = new BoundField();
              bf.HeaderText = headers[c];
              bf.DataField = item;
              bf.ItemStyle.CssClass = "siteFont leftPaddingThree";
              bf.SortExpression = item;
              gv.Columns.Add(bf);
              c++;
            }
        }

I would prefer using the generics, as Mike has posted... but there is still an issue with the line:

bf.HeaderText = StringEnum.GetString((TEnum)c);

The method that it calls needs an Enum and "enumType" as written in Mike's code is not considered an Enum apparently because I get an error "cannot convert from TEnum to System.Enum, here is the method it calls:

        public static string GetString(Enum value)
        {
            string output = null;
            Type type = value.GetType();

            if (_stringValues.ContainsKey(value))
                output = (_stringValues[value] as StringValueAttribute).Value;
            else
            {
                //Look for our 'StringValueAttribute' in the field's custom attributes
                FieldInfo fi = type.GetField(value.ToString());
                StringValueAttribute[] attrs = fi.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];
                if (attrs.Length > 0)
                {
                    _stringValues.Add(value, attrs[0]);
                    output = attrs[0].Value;
                }
            }
            return output;
        }

I did not write the method above (or the StringEnum class)... but here is the method that I added to get the list of enum strings:

        public static List<string> GetStringValueList(Type enumType)
        {
            List<string> values = new List<string>();
            //Look for our string value associated with fields in this enum
            foreach (FieldInfo fi in enumType.GetFields())
            {
                //Check for our custom attribute
                var stringValueAttributes = fi.GetCustomAttributes(typeof(StringValueAttribute), false) as StringValueAttribute[];
                if (stringValueAttributes.Length > 0)
                {
                    values.Add(stringValueAttributes[0].Value);
                }
            }
            return values;
        }

If anyone knows a way that is like Mike's (that uses generics) that I can get this done I'd appreciate it. It is all a matter of learning and knowledge now because I've already implemented the solution that I have above, but I would still like to know how to do this in a truly generic way... thanks!

Barry Franklin
  • 1,781
  • 1
  • 27
  • 45