- The Anatomy of a FieldTemplate.
- Your First FieldTemplate.
- An Advanced FieldTemplate.
- A Second Advanced FieldTemplate.
- An Advanced FieldTemplate with a GridView.
- An Advanced FieldTemplate with a DetailsView.
- An Advanced FieldTemplate with a GridView/DetailsView Project.
Your First FieldTemplate
We’ll create a simple FieldTemplate that displays an enumeration as RadioButtonList.Create Database and Table
We will need a database to run against so in Solution Explorer create a new ASP.Net folder App_Data in the root of the website and create a new Database in there called Animals. Now create a new table called Pets with the following columns.
Figure 1 – Pets Table
Create the Enumeration Type
/// <summary> /// My not very exhaustive set of animals /// </summary> public enum AnimalType { Budgie, Cat, Dog, Gerbil, Hamster, Lizard, Mouse, Parrot, Rat, Snake }
public enum Gender // Added { Male = 0, Female = 1 }
Listing 1 – AnimalType & Gender ***UPDATED***
Create the Model
Add a new Linq to SQL to the App_Code folder and and call it Animals. Copy the Pets table to it. Now we need to set the type of the Pets.Type to AnimalTypes and also do the same for the sex column setting its type to Gender.
Figure 2 - Setting the Pets.Type to the AnimalType enum
Save the and Close the Model.
In the same class file as the enums add your metadata.
using System.ComponentModel.DataAnnotations; using System.ComponentModel; [MetadataType(typeof(PetMetaData))] public partial class Pet { public class PetMetaData { [UIHint("Enumeration")] public object Animal { get; set; } [UIHint("Enumeration")] public object sex { get; set; } } }
Listing 2 – Pet metadata ***UPDATED***
Creating a New FieldTemplate
Expand the DynamicData folder and right-click on the FieldTemplates folder, choose Add New Item… and choose Web User Control from the list of items. Give it the name Enumeration_Edit.ascx
Change the base class that the user control inherits from System.Web.UI.UserControl to System.Web.DynamicData.FieldTemplateUserControl. and a new using System.Web.DynamicData. Change the class name to Enumeration_EditField from DynamicData_FieldTemplates_Enumeration_Edit in both the ascx and code behind files.
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Enumeration.ascx.cs" Inherits="Enumeration_EditField" %>
Listing 3 – Enumeration_Edit.ascx
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.DynamicData; public partial class Enumeration_EditField : System.Web.DynamicData.FieldTemplateUserControl { }
Listing 4 – Enumeration_Edit.ascx.cs code behind
The UserControl is now ready for us to add our code to make it show a DropDownList control populated with AnimalTypes.
Building Our Custom FieldTemplate
Add a DropDownList to the UserControl leave it as DropDownList1 and switch to the code behind.
In the code behind body of the class type protected override On and as you type On you will notice the auto-complete intellisense offer you some options use the arrow keys to select OnDataBinding and hit the tab key (but not too hard or you will break your keyboard :D).
Figure 3 - Auto-Complete Intellisense
Now you should have:
public partial class Enumeration_EditField : System.Web.DynamicData.FieldTemplateUserControl { protected override void OnDataBinding(EventArgs e) { base.OnDataBinding(e); } }
Listing 5 – OnDataBinding event handler
I mentioned the above because I think it’s really neat .
After the base.OnDataBinding(e); line we need to add our code to populate the DropDownList.
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Enumeration_Edit.ascx.cs" Inherits="Enumeration_EditField" %> <asp:DropDownList runat="server" ID="DropDownList1" CssClass="droplist" OnDataBound="DropDownList1_DataBound"> </asp:DropDownList>Listing 6 – Finished Enumeration_Edit.ascx note the OnDataBound
using System; using System.Web.UI; using System.Web.UI.WebControls; public partial class Enumeration_EditField : System.Web.DynamicData.FieldTemplateUserControl { protected override void OnDataBinding(EventArgs e) { // When overriding OnDataBinding be sure to call the base class's // OnDataBinding method so that registered delegates receive the event. base.OnDataBinding(e); // get a data bindable list of permissions for the DDL var enumList = Enum.GetValues(Column.ColumnType); DropDownList1.DataSource = enumList; DropDownList1.DataBind(); } protected override void ExtractValues(System.Collections.Specialized.IOrderedDictionary dictionary) { dictionary[Column.Name] = ConvertEditedValue(DropDownList1.SelectedValue); } protected void DropDownList1_DataBound(object sender, EventArgs e) { // make sure we are in edit mode if (Mode == DataBoundControlMode.Edit) { // try to get an item in the list that matched the FieldValueString ListItem item = DropDownList1.Items.FindByValue(FieldValueString); if (item != null) { // if we get the value set the drop down list to FieldValueString DropDownList1.SelectedValue = FieldValueString; } } } // This is one of those needed things I think it allows // access to the actual control through Controls property public override Control DataControl { get { return DropDownList1; } } }
Listing 7 – Finished Enumeration_Edit.ascx.cs
Now we need an Enumeration.ascx file for this FieldTemplate all we need is to create a copy of the Text.ascx FieldTemplate control.
<%@ Control Language="C#" CodeFile="Enumeration.ascx.cs" Inherits="EnumerationField" %> <asp:Literal runat="server" ID="Literal1" Text="<%# FieldValueString %>" />
using System.Web.UI; public partial class EnumerationField : System.Web.DynamicData.FieldTemplateUserControl { public override Control DataControl { get { return Literal1; } } }Listing 9 – Enumeration.ascx.cs
This blatant copy if the Text.ascx FieldTemplate is due to the fact that our enumeration types don’t have a direct conversion to text and so don’t automatically drop through to the Text.ascx FieldTemplate.
Now we can edit and view our data.
26 comments:
Great Post... Would this work the same way with Entity Framework ?
I don't see why not i've not done anything that is excluded by the EF
Steve
Would you please post a ZIP of the project thanks
Once again, Stephen pulls through! Your blog on all things Dynamic Data has saved me countless hours of pulling my hair out! THANK YOU!
A few things:
Even when changing the database field "Type" to a type of Animal, the properties in the code-behind still remain as Integers, at least when using VB.NET. So I had to find:
private _Type As Integer
and change to:
private _Type As Animal
and correct the properties as necessary (VB.NET doesn't have the nice generic { get; set; } functionality)
Even so, the dropdown I get has only the enumeration name, not the value. I.E.
<option value="Budgie">Budgie</option>
<option value="Cat">Cat</option>
<option value="Dog">Dog</option>
I'm not sure, but I think because the value isn't an integer, it is blowing up for me when I try to update it. Should that be the case, or when it saves is it magically getting the value for the enum and saving it?
The error I get is:
"Microsoft JScript runtime error: Sys.WebForms.PageRequestManagerServerErrorException: Row not found or changed."
What am I doing wrong?
~I'm really sorry but VB.Net makes my head ache, I have had no problems with this setting the type in the Designer.
Steve :D
Please....
Anyone know how to create a new field template for EntityModel??? In LinqModel seens easy.... but in EntityModel? Is it possible? How? I create my field values, but i cant use it by puting uihint on property in design.cs class.
Hi Thiago, send me an e-mail and we can have a chat about your requirements and see what can be done.
Steve :D
Do you have a simple sample like above that you could share? I've been attempting to get this working for the last couple days. I keep getting this error:
Type provided must be an Enum.
Parameter name: enumType
I've set the Type of the column in question in the data model and followed the rest of your example. Looking at a sample that works, may help me out.
Thanks,
Kel
Hi Kel, I can provid the sample if you send me an e-mail to the e-mail address I have on this blog.
Steve :D
Hi
I've got the same error Type provided must be an Enum.
Parameter name: enumType
In Linq to SQL datacontext, i do the same as above with Gender and AnimalType and leave Server Data Type as Int not Null
Nam Vo.
Hi Nam, this will only work with Linq to SQL and you must have the Enum in the same namespace as the dbml or fully qualify it.
Steve
Hi Steve, thanks for the excellent Dynamic Data resources you are providing here - saved me so many headaches. I have just implemented this Enum FieldTemplate, which works great. I was wondering however how to implement something similar to an Enum but permits spaces i.e. the Animal example works ok, but if I was wanting to set the Status of an Order to 'Awaiting Processing' rather than 'AwaitingProcessing'?
HiGareth, try this:
// get a data bindable list of permissions for the DDL
var enumList = Enum.GetValues(enumType);
foreach (var enumItem in enumList)
{
listControl.Items.Add(new ListItem()
{
Text = enumItem.ToString().ToTitleFromPascal(),
Value = enumItem.ToString()
});
}
and here is the extension method ToTitleFromPascal:
public static String ToTitleFromPascal(this String s)
{
// remove name space
String s0 = Regex.Replace(s, "(.*\\.)(.*)", "$2");
// add space before Capital letter
String s1 = Regex.Replace(s0, "[A-Z]", " $&");
// replace '_' with space
String s2 = Regex.Replace(s1, "[_]", " ");
// replace double space with single space
String s3 = Regex.Replace(s2, " ", " ");
// remove and double capitals with inserted space
String s4 = Regex.Replace(s3, "(?[A-Z])\\s(?[A-Z])", "${before}${after}");
// remove and double capitals with inserted space
String sf = Regex.Replace(s4, "^\\s", "");
// force title case i.e. 'this is a title' becomes 'This Is A Title'
return sf.ToTitleCase();
}
public static String ToTitleCase(this String text)
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < text.Length; i++)
{
if (i > 0)
{
if (text.Substring(i - 1, 1) == " " ||
text.Substring(i - 1, 1) == "\t" ||
text.Substring(i - 1, 1) == "/")
sb.Append(text.Substring(i, 1).ToString().ToUpper());
else
sb.Append(text.Substring(i, 1).ToString().ToLower());
}
else
sb.Append(text.Substring(i, 1).ToString().ToUpper());
}
return sb.ToString();
}
public static String ToSentenceCase(this String text)
{
return text.Substring(0, 1).ToUpper() + text.Substring(1, text.Length - 1).ToLower();
}
public static String GetDisplayFormat(this Type type)
{
string defaultFormat = "{0}";
if (type == typeof(DateTime) || type == typeof(Nullable))
{
defaultFormat = "{0:d}";
}
else if (type == typeof(decimal) || type == typeof(Nullable))
{
defaultFormat = "{0:c}";
}
return defaultFormat;
}
Hope this helps:
thanks for the post ... I tried it and it works great for inserting, but it ends up an error on editing and deleting. :-(
Please help.
Hi there I'll look into that as soon as I get a chance, I just got back of vacation and I have a major backlog to attend to :)
Steve
Hi Steve, i want to create RadioButtonList in FieldTemplate, can you tell me how to do that, data should be retrieved from Database not from Enum
Hi Giribabu, can you email me directly e-mail is at the top of the page.
Steve
Hi Steave, I had sent you an e-mail from my company e-mail id.
I want to know the Positives and Negatives of ASP.NET Web Forms with Dynamics.
After creating this sample i inserted values from backend and executed the sample its showing with 3coloumns from DB [ NAME, Gender & Age] when i try to edit that info then error is comming
Type provided must be an Enum.
Parameter name: enumType
even i checked the namespace everything is fine.
Created this sample in VS2008
YOU MENTIONED IN TITLE
"We’ll create a simple FieldTemplate that displays an enumeration as RadioButtonList."
i didn't found any RADIOBUTTONLIST control is used in the code.
Hi giribabu, this is an old sample in VS2010 and .Net 4 DD already has a way of doing Enum field templates this way is out of date.
Steve
Hi Steve,
i tried this in Entity Framework but doesn't seems to work. Do you know the work around fix for entity framework?
Thxu.
Hi Adi, you can't do it this way in EF, what version of DD are you running VS20008 & .Net 3.5 SP1 or VS2010 & .Net 4?
Steve
VB.NET has had the 'generic get set' properties for quite awhile.
It's termed the explicit property setting. If you declare the property in an interface, it has to be explicit. if you declare in the class, you type 'End Property' and than type 'Get' or 'Set' within the property declaration. You'll end up seeing something like this.
Private _Name as DataType
Property PropertyName As DataType
Get
return me._Name 'Private Variable
End Get
Set(value as DataType)
me._Name = value
End Set
End Property
Though, I took the liberty of including the Private variable declaration, return statement, and value assignment.
How to apply below two query in my DD using query extender
select regno, count(regno) as cnt INTO #TEMP1 from MainTable
group by regno having count(regno) >= 2
select * from MainTable where regno in (select regno from #TEMP1) order by regno
Post a Comment