locked
DisplayFormatAttribute doesn't work when this is a ForeignKey DropDownList / Hyperlink RRS feed

  • Question

  • User1826226228 posted

    What i want to do:


     Imagine I have a Flyer table with 2 colunms in my SQl Server:

    • FlyerID (int)(PK)
    • FlyerDate (smalldatetime)

    FlyerID is a foreign key on other tables, for example Store table. Store has 3 columns:

    • StoreID (int)(PK)
    • Name (nvarchar)
    • FlyerID (int)(FK) relationship with Flyer table


    Now, at the DynamicData site, we will have the Stores page and the Flyers page. I want to display FlyerDate using my custom format. The format is MMM-dd-yyyy, for example.

    At the Flyers page, the way I implemented following the tutorial video at: http://www.asp.net/learn/3.5-SP1/video-291.aspx works perfectly, displaying my custom format for the FlyerDate column.

    At the Stores page however, the Flyer column values (which are hyperlinks) don't show the date in my custom format. Also, in the Filter (dropdown list) doesn't show custom format.


    Suggested Failed Solution:

    At: http://ericphan.info/development/asp-net-dynamic-data-display-custom-text-in-a-foreign-key-dropdownlist-combobox. Giving me error "The display column 'DisplayDate' specified for the table does not exist."

    I'm using .Net Framework 4.0 BETA. I'm using Entity Framework.


    Code:

    [DisplayColumn("DisplayDate", "FlyerDate", true)]
        [MetadataType(typeof(FlyerMetadata))]
        public partial class Flyer
        {

            [ScaffoldColumn(true)]
            public string DisplayDate
            {
                get { return this.FlyerDate.ToString("MMM-dd-yyyy"); }
            }

        }

        public class FlyerMetadata
        {
            [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MMM-dd-yyyy}")]
            public DateTime FlyerDate { get; set; }
        }



    What should I do? Please help! Thank you!

    Thursday, January 7, 2010 4:50 PM

Answers

  • User-330204900 posted

    Hi Filhodapuc, if you override the ToString method of your Flyer class you shouls get the dropdown list containing the Data formattes as you required the you could add the DisplayColumn Attribute like below:

    [DisplayColumn("DisplayDate", "FlyerDate", true)]
    [MetadataType(typeof(FlyerMetadata))]
    public partial class Flyer
    {
        public override string ToString()   
        {   
            return FlyerDate.ToString("MMM-dd-yyyy");   
        }
    
        public class FlyerMetadata
        {
            [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MMM-dd-yyyy}")]
            public DateTime FlyerDate { get; set; }
        }
    }

    I know this is the same as I have shown before I have just tested it with Northwind DB and it works fine see:

    ddl with date in descending order

    Hope this helps [:D]

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, January 16, 2010 9:25 AM

All replies

  • User-330204900 posted

    You are better overriding the ToString method like this:

    [MetadataType(typeof(FlyerMetadata))]
    public partial class Flyer
    {
        public override string ToString()
        {
            return this.CreatedDate = DateTime.Now.ToString("MMM-dd-yyyy");
        }
    }
    

    if you want a field in the DB set to the dateTime it was created then you could do this by overriding the table Insert method (I am assuming you are using Linq to SQL and not Entity Framework) like this:

    public partial class NorthwindDataContext
    {
        partial void InsertCustomer(Customer instance)
        {
           instance.CreationDate = DateTime.Now;
           this.ExecuteDynamicInsert(instance);
        }
    }
    

    And then you could just display the CreationDate filed in you DDL the other advantage is that custom fields will not sort on because the sort is done in the DB so if you have a DB field like above then you can sort on it and get the effect you want.

    Friday, January 8, 2010 3:22 AM
  • User1826226228 posted

    Please read again my post. I'm sorry for my poor explanation before, it was bad. But did you understand now?


    Friday, January 8, 2010 12:48 PM
  • User-330204900 posted

    OK so your Metadata could look somtning like:

    [DisplayColumn("DisplayDate", "FlyerDate", true)]
    [MetadataType(typeof(FlyerMetadata))]
    public partial class Flyer
    {
        public override string ToString()   
        {   
            return this.CreatedDate = FlyerDate .ToString("MMM-dd-yyyy");   
        }
    
        public class FlyerMetadata
        {
            [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MMM-dd-yyyy}")]
            public DateTime FlyerDate { get; set; }
        }
    }


    I'll give this a test when I get back in later, but I think it is correct [:D]

     

    Friday, January 8, 2010 1:29 PM
  • User1826226228 posted

    Please read again my post. I fixed.


    Friday, January 8, 2010 2:11 PM
  • User-330204900 posted

    No problem glad you fixed it [:)] 

    Friday, January 8, 2010 4:36 PM
  • User1826226228 posted

    Sorry Steve,

    I didn't mean I fixed my problem. I meant I fixed my post because you were not understading my problem. Could you please read again my post from the beggining or do you want me to create a new topic?



    Friday, January 8, 2010 6:38 PM
  • User-330204900 posted

    I'll read through it again and try and get it this time [:D] 

    Friday, January 8, 2010 7:05 PM
  • User-330204900 posted

    Hi Filhodapuc, if you override the ToString method of your Flyer class you shouls get the dropdown list containing the Data formattes as you required the you could add the DisplayColumn Attribute like below:

    [DisplayColumn("DisplayDate", "FlyerDate", true)]
    [MetadataType(typeof(FlyerMetadata))]
    public partial class Flyer
    {
        public override string ToString()   
        {   
            return FlyerDate.ToString("MMM-dd-yyyy");   
        }
    
        public class FlyerMetadata
        {
            [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MMM-dd-yyyy}")]
            public DateTime FlyerDate { get; set; }
        }
    }

    I know this is the same as I have shown before I have just tested it with Northwind DB and it works fine see:

    ddl with date in descending order

    Hope this helps [:D]

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, January 16, 2010 9:25 AM
  • User1826226228 posted

    Thank you! This is beautiful and yet so simply. I didn't see clear before cause you used the this.CreateDate in it, but i get it now. Thank you!


    Hi Filhodapuc, if you override the ToString method of your Flyer class you shouls get the dropdown list containing the Data formattes as you required the you could add the DisplayColumn Attribute like below:

    1. [DisplayColumn("DisplayDate""FlyerDate"true)]  
    2. [MetadataType(typeof(FlyerMetadata))]  
    3. public partial class Flyer  
    4. {  
    5.     public override string ToString()     
    6.     {     
    7.         return this.CreatedDate = FlyerDate .ToString("MMM-dd-yyyy");     
    8.     }  
    9.   
    10.     public class FlyerMetadata  
    11.     {  
    12.         [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MMM-dd-yyyy}")]  
    13.         public DateTime FlyerDate { getset; }  
    14.     }  
    15. }  
    [DisplayColumn("DisplayDate", "FlyerDate", true)]
    [MetadataType(typeof(FlyerMetadata))]
    public partial class Flyer
    {
        public override string ToString()   
        {   
            return this.CreatedDate = FlyerDate .ToString("MMM-dd-yyyy");   
        }
    
        public class FlyerMetadata
        {
            [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:MMM-dd-yyyy}")]
            public DateTime FlyerDate { get; set; }
        }
    }

    I know this is the same as I have shown before I have just tested it with Northwind DB and it works fine see:

    ddl with date in descending order

    Hope this helps Big Smile


    Saturday, January 16, 2010 10:15 AM
  • User-330204900 posted

    I didn't see clear before cause you used the this.CreateDate in it, but i get it now.
     

    Sorry about that it was pasting from me [:$]

    Saturday, January 16, 2010 10:51 AM
  • User1014298547 posted

    Great answer! But can this be done with two fields?

    In my situation, I am creating a Dynamic Data site that keeps records for our crews that go out to ships for equipment repairs. They visit the ship and write up serveral work orders on that visit. So I have a Visits table with a one to many relationship with a Work Order table (one Visit has many Work Orders). There is a ShipName and a StartDate field in the Visits table. I want to filter the Work Orders list page using a drop down that displays the ShipName and the StartDate sorted first by ShipName and then by StartDate.

    After scouring the web, I came up with the following (in visits metadata):

        [MetadataType(typeof(VisitMetaData))]
        [ScaffoldTable(true)]
        [DisplayColumn("VisitList")]
        public partial class Visit
        {
     
            [ScaffoldColumn(true)]
            public string VisitList
            {
                get
                {
                    return ShipName.ToString() + StartDate.ToString();
                }
            }
           
            public partial class VisitMetaData
            {
                [ScaffoldColumn(false)]
                [Display(Name = "VisitID")]
                public Object VisitID { getset; }
              
                [ScaffoldColumn(true)]
                [Display(Name = "Ship Name")]
                public Object ShipName { getset; }
     
                [ScaffoldColumn(true)]
                [Display(Name = "Start Date")]
                public Object StartDate { getset; }
            }
        }

    But I keep getting "The sort column 'DisplayVisits' specified for the table 'Visits' does not exist." error on the page at runtime.

    So I tried this variation, based on your answer:

        [MetadataType(typeof(VisitMetaData))]
        [ScaffoldTable(true)]
        [DisplayColumn("ShipName""ShipName")]
        public partial class Visit
        {
            public override string ToString()
            {                 
                return this.ShipName + this.StartDate; 
            }
     
            public partial class VisitMetaData
            {
                [ScaffoldColumn(false)]
                [Display(Name = "VisitID")]
                public Object VisitID { getset; }
                
                
                [ScaffoldColumn(true)]
                [Display(Name = "Ship Name")]
                public Object ShipName { getset; }
     
                [ScaffoldColumn(true)]
                [Display(Name = "Start Date")]
                public Object StartDate { getset; }
     
            }
        }

    This works, but it only sorts by ShipName, not by ShipName then StartDate.

    You mentioned that using the override methods is perferred, so how can I do it by using, and then sorting two fields?

    Wednesday, December 12, 2012 3:15 PM
  • User-330204900 posted

    Yes this works I use it all the time. you cannot sort by two column using the DisplayColumn attribute, I recently created a multi column sort attribute and extension method see below:

    [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    public class MultiColumnSortAttribute : Attribute
    {
        private char[] splitChars = new char[] { ',' };
        public Dictionary<String, SortDirection> Columns { get; set; }
    
        public MultiColumnSortAttribute(params String[] columns)
        {
            Columns = columns.ToDictionary(x => x.Split(splitChars)[0], x => x.Split(splitChars)[1].ToEnum<SortDirection>());
        }

    it's not quite ready for prime time but it will add the sort to your project

    public static class QueryExtenderExtensionMethods
    {
        /// <summary>
        /// Sets the initial sort order.
        /// </summary>
        /// <param name="queryExtender">The query extender.</param>
        /// <param name="table">The table.</param>
        public static void SetInitialSortOrder(this QueryExtender queryExtender, MetaTable table)
        {
            var multiColumnSort = table.GetAttribute<MultiColumnSortAttribute>();
            if (multiColumnSort != null)
            {
                var firstEntry = multiColumnSort.Columns.Keys.First();
                var order = new OrderByExpression()
                {
                    DataField = firstEntry,
                    Direction = multiColumnSort.Columns[firstEntry],
                };
    
                foreach (var item in multiColumnSort.Columns)
                {
                    if (item.Key != firstEntry)
                    {
                        order.ThenByExpressions.Add(new ThenBy()
                        {
                            DataField = item.Key,
                            Direction = item.Value
                        });
                    }
                }
                queryExtender.Expressions.Add(order);
            }
            else if (table.SortColumn != null)
            {
                var order = new OrderByExpression()
                {
                    DataField = table.SortColumn.Name,
                    Direction = table.SortDescending ? SortDirection.Descending : SortDirection.Ascending,
                };
                queryExtender.Expressions.Add(order);
            }
        }
    }

    apply the attribute to you metadata in the same place you use the DisplayColumn attribute

    [MultiColumnSort("Department,Ascending""Name,Ascending")]
    

    Note that these are in pairs I will sort this so it is not magic strings soon.

    Hope this helps I will post in full on my blog when done

     

     

    Thursday, December 13, 2012 5:17 AM
  • User-330204900 posted

    Oops L I forgot to add the other extension methods, so sorry I’m a dope J so this extension method needs to be in a static class

    public static class EnumExtensionMethods
    {
        /// <summary>
        /// Toes the enum.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="enumString">The enum string.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static T ToEnum<T>(this String enumString) //where T : Enum
        {
            var value = Enum.Parse(typeof(T), enumString);
            return (T)value;
        }
    }

    I think that should fix it.

    Thursday, December 20, 2012 9:02 AM
  • User1014298547 posted

    No problem Steve!

    This is something that Microsoft should be addressing anyway. It's not unusual in real world applications to have a drop-down that displays more than one column and for both of these columns to be sorted.

    Dynamic Data is a great idea, but it seems to me that Microsoft still hasn't taken it far enough to be practical for production level applications. Maybe that is why it hasn't been fully embraced by the ASP.NET developer community. Hopefully this issue, along with several other short-comings will be addressed in future releases.

    You've been addressing other Dynamic Data issues as well and you shouldn't be doing this all by yourself.  This might be hard to believe, but I'm sure that you, like other developers, have a life beyond just writing code! We simply don't have enough time work our regular jobs and write code for Microsoft in our free time!

    Anyway, thanks for all of your effort!

    Thursday, December 20, 2012 9:56 AM