Comanighttrain
Comanighttrain

Reputation: 247

How to bind a custom Enum description to a DataGrid

Problem: I have an enumerated type which has description tags in the following style: [URL="http://xml.indelv.com/data-binding-enum.html"]description tag tutorial[/URL] . I have a Windows SQL Server Database from which I am pulling the data (as integers then castine to Enums) which is then being bound to a datagrid. Instead of pulling and casing the enumerated types, I would like to display the description tag associated with it in the enumerated type.

Here is the ASP -

<asp:GridView ID="StatementGrid" runat="server" AutoGenerateColumns="false" DataKeyNames="statementID" OnRowDeleting="StatementGrid_onDeleting" AllowSorting="False">
                <Columns>
                    <asp:BoundField HeaderText="Type" SortExpression="type" DataField="TypeOfStatement" />
                    <asp:HyperLinkField HeaderText="Statement" DataTextField="StatementText" DataNavigateUrlFormatString="~/Gateway/Statements/View.aspx?statementID={0}" SortExpression="statement" DataNavigateUrlFields="statementID" />
                    <asp:HyperLinkField DataNavigateUrlFields="statementID" DataNavigateUrlFormatString="~/Gateway/Statements/Update.aspx?statementID={0}" NavigateUrl="~/Gateway/Statements/Update.aspx" HeaderText="Edit" Text="<img src='../../Images/News/news_edit.gif' alt='Edit Statement'/>" />
                    <asp:TemplateField HeaderText="Delete">
                        <ItemTemplate>
                            <asp:ImageButton AlternateText="Delete Statement" ID="DeleteButton" ImageUrl="~/Images/News/news_delete.gif" runat="server" CommandName="Delete" OnClientClick="javascript:return confirm('Are you sure you want to delete this statement?');" />
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
                <EmptyDataTemplate>
                    There are no statements to display.
                </EmptyDataTemplate>
            </asp:GridView>

Here is the code for the Bind -

[CODE]

private void BindData()
        {
            IStatementDao statementDao = DaoFactory.GetStatementDao();
            List<Statement> statements;

            if (Page.Request.RawUrl.Contains("Gateway"))
            {
                statements = statementDao.GetAll();

                StatementGrid.HeaderStyle.CssClass = "GatewayGridHeader";
                StatementGrid.AlternatingRowStyle.CssClass = "GatewayGridAlternatingRow";

            }
            else
            {
                // This should never be reached but it keeps the compiler happy!!
                statements = statementDao.GetAll();
            }

            StatementGrid.DataSource = statements;
            StatementGrid.DataBind();
            DisplayTypeDescriptors();
        }

[/CODE]

Here is the enumerated class -

[CODE]

public enum TypeOfStatement 
        { 
            [EnumDescription("Dress Code")] DressCode = 1,
            [EnumDescription("Lunch Time")] LunchTime = 2,
            [EnumDescription("Footwarez")] Footware = 3,
            [EnumDescription("achtung")] Warning = 4,
            [EnumDescription("Banarna")] Banana = 5,
            [EnumDescription("Apfel")] Apple = 6
        };c#

[/CODE]

Its obvious that one could write an extensive method do do what i want, but is there a neater way?

Upvotes: 2

Views: 5841

Answers (1)

ShuggyCoUk
ShuggyCoUk

Reputation: 36438

Wrap them up on the fly and subtly change your handling of the SelectedItem (or whatever you are using)
My example uses the already present Description attribute.

public class DescriptiveEnum<T> where T: struct
{
    private static readonly Dictionary<T,string> descriptions 
        = new Dictionary<T,string>();

    static DescriptiveEnum()
    {
        foreach (FieldInfo field in
            typeof(T).GetFields(BindingFlags.Static 
            | BindingFlags.GetField | BindingFlags.Public))
        {
        descriptions.Add((T)field.GetRawConstantValue(),
            LookupName(field));         
        }
    }

    public readonly T Value;

    public DescriptiveEnum(T value)
    {
        this.Value = value;     
    }

    public override string ToString()
    {
        string s;
        if (!descriptions.TryGetValue(this.Value, out s))
        {           
        // fall back for non declared fields
        s = this.Value.ToString();  
        descriptions[this.Value] = s;
        }
        return s;
    }

    private static string LookupName(FieldInfo field)        
    {
        object[] all = field.GetCustomAttributes(
             typeof(DescriptionAttribute), false);
        if (all.Length == 0)
            return field.Name; // fall back
        else
            return ((DescriptionAttribute)all[0])
                .Description; // only one needed
    }   

    public static BindingList<DescriptiveEnum<T>> Make(
        IEnumerable<T> source)
    {
        var list = new BindingList<DescriptiveEnum<T>>();
        foreach (var x in source)
        list.Add(new DescriptiveEnum<T>(x));
        return list;
    }
}

example usage:

public enum Foo
{
    [Description("flibble")]
    Bar,
    [Description("wobble")]
    Baz,
    // none present, will use the name
    Bat

}

Form f = new Form();
f.Controls.Add(new ListBox() 
{
    Dock = DockStyle.Fill,
    DataSource = DescriptiveEnum<Foo>.Make(
       new Foo[] { Foo.Bar, Foo.Baz, Foo.Bat }),
});
Application.Run(f);

Upvotes: 2

Related Questions