locked
rules-based generic approach to get friendly column names in a Dynamic Data project RRS feed

  • Question

  • User-1614457691 posted

    All --

    Please help.

    I am looking for a rules-based generic approach to get friendly column names in a Dynamic Data project.

    For instance, suppose I use a rule to name my columns in the database that separates words with PascalCased names-- FirstName, LastName, MiddleName, and so on.

    Now, suppose that I want to have a rules-driven friendly name creation done automatically by the Dynamic Data templating process to convert such names "insert space if next is capital" so we get... First Name, Last Name, MIddle Name.

    Or something like that. Maybe the rule is "replace underscores in the database column name with a space in the display name"-- from First_Name, Last_Name to First Name and Last Name etc.

    Rules to be worked out later.

    How can such rules be applied generically, so that I don't have to manually specify something like DisplayName="First Name" everytime I need an adjustment?

    I really like the way the templates are applied generically in they Dynamic Data approach, so a template has no knowledge of column names-- I want to preserve that approach.

    I would not mind making a custom helper method, "GetFriendlyColumnName(string databaseColumnName)", but I do not know where to plug that in.

    Do you have any ideas how this can be done?

    Please advise.

    Thank you.

    -- Mark Kamoski

    Saturday, August 23, 2008 1:49 PM

Answers

  • User-330204900 posted

    Hmmm yes! Sorry I got my threads confused [:$]

    I back on the right track now [;)]

    I've just gone back to the code I posted at first and re tested update insert and delete work fine, if you could post any errors you get I'll look into it.

    also here is the project file that I just tested here: DD|_ColumnNames

    Hope this helps [:D]

    P.S. Sorry about the way that LiveDrive link works the Iframe won't embed in the page [:(]

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, September 13, 2008 9:02 AM

All replies

  • User-797310475 posted

     Hi Mark,

    first of all one thing to note is that Dynamic Data uses the names provided by your model. It does not have a way to query the database itself for such things. So you would have to ensure that the model reproduces the names the way you want them.

    Regarding the specifics of your question, the only way of achieving this would be to modify all of the field templates and replace all calls to MetaTable.DisplayName with calls to your own function. This is what we are doing in the Dynamic Data Futures project to work around the fact that DisplayName attribute is not localizable.

    Saturday, August 23, 2008 5:11 PM
  • User-330204900 posted

    I would not mind making a custom helper method, "GetFriendlyColumnName(string databaseColumnName)", but I do not know where to plug that in.

    I thought some thing like this would do what you want:

    using System.Collections;
    using System.Collections.Generic;
    using System.Web.DynamicData;
    using System.Web.UI;
    
    public class ColumnNameFieldsManager : IAutoFieldGenerator
    {
    	protected MetaTable _table;
    
    	public ColumnNameFieldsManager(MetaTable table)
    	{
    		_table = table;
    	}
    
    	public ICollection GenerateFields(Control control)
    	{
    		List<DynamicField> oFields = new List<DynamicField>();// Note the missing <DynamicField> 
    
    		foreach (MetaColumn column in _table.Columns)
    		{
    
    			// carry on the loop at the next column  
    			// if scaffold table is set to false or DenyRead
    			if (!column.Scaffold)
    				continue;
    
    			DynamicField f = new DynamicField();
    
    			f.DataField = column.Name;
    			f.HeaderText = "***" + column.Name + "***";
    			oFields.Add(f);
    		}
    		return oFields;
    	}
    }

    By addind a class that implements IAutoFielsGenerator (above) you can do what you want with the DynamicField.

    Also in the each page's Page_Load event handler you will need to add:

    protected void Page_Load(object sender, EventArgs e)
    {
    	table = GridDataSource.GetTable();
    	Title = table.DisplayName;
    
    	GridView1.ColumnsGenerator = new ColumnNameFieldsManager(table);
    
    	InsertHyperLink.NavigateUrl = table.GetActionPath(PageAction.Insert);
    
    	// Disable various options if the table is readonly
    	if (table.IsReadOnly)
    	{
    		GridView1.Columns[0].Visible = false;
    		InsertHyperLink.Visible = false;
    	}
    }
    Hope this helps [:D]
    Saturday, August 23, 2008 5:45 PM
  • User-1614457691 posted

    ...Regarding the specifics of your question, the only way of achieving this would be to modify all of the field templates and replace all calls to MetaTable.DisplayName with calls to your own function. This is what we are doing in the Dynamic Data Futures project to work around the fact that DisplayName attribute is not localizable.


    I appreciate the excellent response.

    Will the same technique that you describe above work for the table names too?

    If not, then how can that be accomplished?

    Please advise.

    Thank you.

    -- Mark Kamoski

    Tuesday, August 26, 2008 6:59 AM
  • User-1614457691 posted

    I thought some thing like this would do what you want:

    ...
    public class ColumnNameFieldsManager : IAutoFieldGenerator
    {
    ...
    Also in the each page's Page_Load event handler you will need to add:
    protected void Page_Load(object sender, EventArgs e)
    {
    	table = GridDataSource.GetTable();
    	Title = table.DisplayName;
    
    	GridView1.ColumnsGenerator = new ColumnNameFieldsManager(table);
    
    ...
    
    
    
    
    That looks like a nice approach for Grids, on a page-by-page basis.
    However, I am having a hard time seeing how to apply this for a detail-view-form or a detail-edit-form or the like.
    Can you explain?
    Please advise.
    Thank you.
    -- Mark Kamoski
    Tuesday, August 26, 2008 7:05 AM
  • User660823006 posted

    Mark,

    Two of our controls support the IAutoFieldGenerator and those are GridView and DetailsView. To do the same technique Steve was showing with DetailsView you would assign the IAutoFieldGenerator to the RowGenerator property on the DetailsView.

    Tuesday, August 26, 2008 12:00 PM
  • User-1910744540 posted

    I found this page:

    http://mattberseth.com/blog/2008/08/dynamic_data_and_custom_metada.html

    It loops through fields looking for DisplayName and if finding none it adds the displayname attribute created using a PascalToHuman function to insert spaces..

    Dont quite get why he setts scaffolding to false - but output looks good.

    Mark

    Wednesday, August 27, 2008 6:29 PM
  • User-1614457691 posted


    ...I thought some thing like this would do what you want...

    sjnaughton --

    I appreciate that.

    However, I am getting some compile-time errors, as noted below.

    I think that I may be able to hack my way around them-- but, I thought that I should check with you too.

    Can you help?

    The offending code is noted below...

    using System.Collections;
    using System.Collections.Generic;
    using System.Web.DynamicData;
    using System.Web.UI;

    public class ColumnNameFieldsManager : IAutoFieldGenerator
    {
     protected MetaTable _table;

     public ColumnNameFieldsManager(MetaTable table)
     {
      _table = table;
     }

     public ICollection GenerateFields(Control control)
     {
      List oFields = new List();

                    //The previous line of code causes the following 2 compile-time-errors.

      //Error 1 
      //Using the generic type 'System.Collections.Generic.List<T>'
      //requires '1' type arguments 
      //C:\Code\Team\Methods2\Web\App_Code\ColumnNameFieldsManager.cs 18 3 C:\...\Web\

      //Error 2 Using the generic type
      //'System.Collections.Generic.List<T>' requires
      //'1' type arguments 
      //C:\Code\Team\Methods2\Web\App_Code\ColumnNameFieldsManager.cs 18 22 C:\...\Web\

      foreach (MetaColumn column in _table.Columns)
      {

       // carry on the loop at the next column 
       // if scaffold table is set to false or DenyRead
       if (!column.Scaffold)
        continue;

       DynamicField f = new DynamicField();

       f.DataField = column.Name;
       f.HeaderText = "***" + column.Name + "***";
       oFields.Add(f);
      }
      return oFields;
     }
    }

    Thursday, August 28, 2008 4:39 PM
  • User-797310475 posted

    List<> is a generic class. You have to declare it as List<object> or something similar. You can also use the non-generic ArrayList.

    Thursday, August 28, 2008 4:49 PM
  • User-1614457691 posted

    List<> is a generic class. You have to declare it as List<object> or something similar. You can also use the non-generic ArrayList.

    I switched to ArrayList. 

    I tried that as generic (I think) but I still get a compile-time error, as shown is this offending code below... 


    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Collections;
    using System.Collections.Generic;
    using System.Web.DynamicData;
    using System.Web.UI;


    public class ColumnNameFieldsManager : IAutoFieldGenerator
    {
     protected MetaTable _table;

     public ColumnNameFieldsManager(MetaTable table)
     {
      _table = table;
     }

     public ICollection GenerateFields(Control control)
     {
      //old... 1...
      //List oFields = new List();

      //Error 1 Using the generic type
      //'System.Collections.Generic.List<T>' requires '1'
      //type arguments 
      //C:\Code\Team\Methods2\Web\App_Code\ColumnNameFieldsManager.cs 22 3 C:\...\Web\

      //old... 2...
      List<object> oFields = new List();

      //Error 1 Using the generic type
      //'System.Collections.Generic.List<T>'
      //requires '1' type arguments 
      //C:\Code\Team\Methods2\Web\App_Code\ColumnNameFieldsManager.cs 30 30 C:\...\Web\

      foreach (MetaColumn column in _table.Columns)
      {
       // carry on the loop at the next column 
       // if scaffold table is set to false or DenyRead
       if (!column.Scaffold)
        continue;

       DynamicField f = new DynamicField();

       f.DataField = column.Name;
       f.HeaderText = "***" + column.Name + "***";

       oFields.Add(f);
      }

      return oFields;
     }
    }
     

     

    Thursday, August 28, 2008 4:56 PM
  • User-797310475 posted

    You also need to apply the generic type in the constructor:

    List<object> list = new List<object>();
     You can read about generics and how to use them here.
    Thursday, August 28, 2008 5:09 PM
  • User-330204900 posted

    Sorry about this I've had this issue before with pasting into here generics List<object> drops the <object> here's the code with out highlighting:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Web.DynamicData;
    using System.Web.Security;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    public class ColumnNameFieldsManager : IAutoFieldGenerator
    {
     protected MetaTable _table;

     public ColumnNameFieldsManager(MetaTable table)
     {
      _table = table;
     }

     public ICollection GenerateFields(Control control)
     {
      List<DynamicField> oFields = new List<DynamicField>();

      foreach (MetaColumn column in _table.Columns)
      {

       // carry on the loop at the next column 
       // if scaffold table is set to false or DenyRead
       if (!column.Scaffold)
        continue;

       DynamicField f = new DynamicField();

       f.DataField = column.Name;
       // do your column name look up here
       f.HeaderText = "***" + column.Name + "***";
       oFields.Add(f);
      }
      return oFields;
     }
    }

    Sorry again I'll try harder next time [;)]

    Hope this helps [:D]

    Thursday, August 28, 2008 5:34 PM
  • User-1614457691 posted

    ...here's the code with out highlighting...

    That works great for the read-only gridview and the read-only detailsview pages.

    When we use it for the detailsview insert or detailsview update, it looks good but the save fails.

    Can you help?

    Thursday, September 11, 2008 2:21 PM
  • User-330204900 posted

    I'll look into insert and update on the details view tomorrow and get back to you. [:D]

    Thursday, September 11, 2008 3:48 PM
  • User-330204900 posted

    <STRIKE>The ParentDetails should not be used for Insert as there can only be one parent in a one to many relationship, so insert does not make any sense.</STRIKE>

    <STRIKE>So i should not have given the option, I will however look into the update business.</STRIKE>

    Sorry got my threads confused [:$]

    Thursday, September 11, 2008 4:05 PM
  • User-330204900 posted

    <STRIKE>Hi I've just tested the PartentDetails FieldTemplate with the Northwind database and Updates work fine. I suggest you try the project I uploaded with Northwind before you ge back to your own.</STRIKE>

    <STRIKE>Hope this helps [:D]</STRIKE>

    Sorry got my threads confused [:$]

    Thursday, September 11, 2008 4:20 PM
  • User-1614457691 posted

    The ParentDetails should not be used for Insert as there can only be one parent in a one to many relationship, so insert does not make any sense.

    So i should not have given the option, I will however look into the update business.

    FYI, it works for everything EXCEPT insert. That is... ...it does work for List (gridview)... ...it does work for DetailView with mode=update... ...it does work for DetailView with mode=view... ...but it does NOT work for DetailView with mode=insert Please ignore my conments in my previous post where I suggested it did not work for update-- that was wrong-- it does work for update. -- Mark Kamoski
    Friday, September 12, 2008 5:40 AM
  • User-330204900 posted

    <STRIKE>I know and I can't think of a reason why you would want to create a new parent from a child so you would then have two parents. Dynamic Data at the moment does not support Many to Many relationships which this would then be?</STRIKE>

    <STRIKE>What do you think?</STRIKE>

    <STRIKE>I'm sure if you can come up with a valid scenario I could get it working.</STRIKE>

    Sorry got my threads confused [:$]

    Friday, September 12, 2008 6:27 AM
  • User-1614457691 posted

    I know and I can't think of a reason why you would want to create a new parent from a child so you would then have two parents. Dynamic Data at the moment does not support Many to Many relationships which this would then be?

    What do you think?

    I'm sure if you can come up with a valid scenario I could get it working.

    Hmmm. Our conversation may have become disconnected. The simple test case that I am using has just one table. As such, relations are not an issue. Recall that I am just trying to change my db column names like first_name to UI-friendly text like-- first name. Intercepting the column generator with the code above works for all templates except insert. Maybe I am not being clear enough here. I am not sure why you brought up parent-child relations because they do not apply to my test case. Do you see my issue?
    Saturday, September 13, 2008 8:34 AM
  • User-330204900 posted

    Hmmm yes! Sorry I got my threads confused [:$]

    I back on the right track now [;)]

    I've just gone back to the code I posted at first and re tested update insert and delete work fine, if you could post any errors you get I'll look into it.

    also here is the project file that I just tested here: DD|_ColumnNames

    Hope this helps [:D]

    P.S. Sorry about the way that LiveDrive link works the Iframe won't embed in the page [:(]

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Saturday, September 13, 2008 9:02 AM
  • User-1614457691 posted

    Great.

     Thank you.

    Friday, September 26, 2008 10:30 PM