I answered this Re: Display multiple fields in custom FieldTemplateUserControl question in the Dynamic Data forum whilst away and didn’t have the time to do a full write up of it so here it is.
What the question was:
Adult wrote “I want to display multiple fields in one custom FieldTemplateUserControl. For example i have property X and Y. Currently they show on separate row when i edit or insert.
Do i need to create new property to return anonymous class with just this 2 property and in custom control,read values.What about inserting? Anyone done it?”
So here’s the partial class I added to deal with the new property Coordinate:
using System.ComponentModel; using System.ComponentModel.DataAnnotations; [MetadataType(typeof(TestPointMD))] public partial class TestPoint { [ScaffoldColumn(true)] public Point Coordinate { get { return new Point(this.X, this.Y); } set { this.X = value.X; this.Y = value.Y; } } public class TestPointMD { public object Id { get; set; } public object Name { get; set; } [ScaffoldColumn(false)] public object X { get; set; } [ScaffoldColumn(false)] public object Y { get; set; } } } [Serializable] public class Point { public Point(int x, int y) { X = x; Y = y; } public int X { get; set; } public int Y { get; set; } public String ToString() { return X + ", " + Y; } }
Listing 1 – Partial methods for my model
Listing 1 consists of three parts:
- The partial class with the Coordinate property added.
- The Metadata class setting the ScaffoldColumn attribute to false for the individual column we don’t want to show.
- And last the Point class that we are using in the Coordinate property Note the Serializable attribute which is needed for the FieldTemplate to be able to return values.
The next part are the FieldTemplates Point and Point_Edit.
<%@ Control Language="C#" CodeFile="Point.ascx.cs" Inherits="PointField" %> <asp:Literal runat="server" ID="Literal1" />
using System; using System.Web.UI; public partial class PointField : System.Web.DynamicData.FieldTemplateUserControl { public override Control DataControl { get { return Literal1; } } protected override void OnDataBinding(EventArgs e) { var p = FieldValue as Point; Literal1.Text = p.ToString(); base.OnDataBinding(e); } }
Listings 2 and 3 are based on the Text.ascx FieldTemplate the main difference is that the value of the literal is set via the Point class’s ToString() method.
<%@ Control Language="C#" CodeFile="Point_Edit.ascx.cs" Inherits="Point_EditField" %> <asp:TextBox ID="TextBoxX" runat="server" CssClass="droplist"> </asp:TextBox> <asp:TextBox ID="TextBoxY" runat="server" CssClass="droplist"> </asp:TextBox>
using System; using System.Collections.Specialized; using System.Web.UI; public partial class Point_EditField : System.Web.DynamicData.FieldTemplateUserControl { protected void Page_Load(object sender, EventArgs e) { TextBoxX.MaxLength = Column.MaxLength; TextBoxY.MaxLength = Column.MaxLength; if (Column.MaxLength < 20) { TextBoxX.Columns = Column.MaxLength; TextBoxY.Columns = Column.MaxLength; } TextBoxX.ToolTip = Column.Description; TextBoxY.ToolTip = Column.Description; } protected override void OnDataBinding(EventArgs e) { var p = FieldValue as Point; if (p != null) { TextBoxX.Text = p.X.ToString(); TextBoxY.Text = p.Y.ToString(); } base.OnDataBinding(e); } protected override void ExtractValues(IOrderedDictionary dictionary) { int x; int y; int.TryParse(TextBoxX.Text, out x); int.TryParse(TextBoxY.Text, out y); var p = new Point(x, y); dictionary[Column.Name] = p; } public override Control DataControl { get { return TextBoxX; } } }
Listing 5 – Point_Edit.ascx.cs
Here in Listings 4 and 5 we create again from the Text_Edit FieldTemplate our Point_Edit FieldTemplate everything in this apart from the ExtractValues method is the same as the FieldTemplate it is based on but just doubled up on the two TextBoxes we have used. In the ExtractValues method we create and populate a new instance of the Point class set it’s X and Y properties and then put it in the dictionary passed into the method.
Figure 1 – Point FieldTemplate in action
This seems to work really well for this type of compound property. At a later date I would like to try this with Point being a User Defended Type in SQL Server 2005/2008, this would get rid of the need for the compound property and would mean only a new FieldTemplate was required.
The combined property does get assigned, but when the update check is on, it ends up being overwritten by the original values of the individual fields. Basically, pretty random results. I think it’s best to avoid using custom properties, especially since they’re not supported in EF.
See Scott’s sample http://www.codeplex.com/aspnet/Release/ProjectReleases.aspx?ReleaseId=14473.
2 comments:
Just wanted to leave a comment.
Thank you, this is exactly what I needed. I just spent 2 days looking for an example implementation like this...Microsoft's documentation wasn't nearly as clear as this.
Hi There I now use computed columns for this sort of thing :)
Steve
Post a Comment