Thursday, November 12, 2009

Creating a Decimal Dynamic Data control that allows commas

I love the Dynamic Data architecture. I won’t get into how it all works, and assume you understand how to use the Decimal Dynamic Data control. For the most part, you never have to worry about it except maybe decorate your Entity with [UIHint (“Decimal”)].

Just open up your project that is a Dynamic Data project in Visual Studio 2008 and go to the DynamicData directory it created for you. Download the my two files (DecimalAllowingCommas_Edit.ascx.cs and DecimalAllowingCommas_edit.ascx) and put them in the FieldTemplates directory. Don’t forget to change your namespace and references to it.

The two files are slightly modified versions of the Decimal_Edit.ascx and Decimal_Edit.ascx.cs files that are already in that directory.

The difference is that I removed the CompareValidator and replaced it with a RegularExpressionValidator since the CompareValidator doesn’t allow for commas in the textfield, but my regular expression does. I also add a line in the Page_Load for this control that sets the ValidationGroup to the same as the other validators in that control. That gives us basically the same validation as we had before, but with commas allowed.

That handled the JavaScript validation and even server side validation, but when the values are automatically pushed to the properties on the entity which are of type double, .Net throws an exception that basically says it can’t convert the string to a double because it has commas in it. Seems a bit silly to me that it can’t do that, but we’ll fix that. I just removed the contents of the ExtractValues method and replaced them with my own that use the Decimal.TryParse() method to do the parsing. This method happily accepts the commas.

Now that we have support for our new type of Dynamic Data control, we need to use it. That is easy. In your entity where you had [UIHint(“Decimal”)], just replace that with [UIHint(“DecimalAllowingCommas”)]. Now when the UI renders editable version of that field it will use the DecimalAllowingCommas_Edit instead of the Decimal_Edit Dynamic Data Control.

On last thing, you will need make sure the ApplyFormatInEditMode property is set to true for the declaration of the DynamicControl in your parent control or page. Here is a the idea of what I am saying talking about.

<asp:FormView>
<EditItemTemplate>
<asp:DynamicControl
ID="CostPerYearDynamicControl" runat="server"
DataField="CostPerYear" Mode="Edit"
ValidationGroup="Edit"
ApplyFormatInEditMode="True"/>
</EditItemTemplate>
</asp:FormView>

 

Here is the source for the .ascx in case you don’t want to download the file.

<%@ Control Language="C#" CodeFile="DecimalAllowingCommas_Edit.ascx.cs" Inherits="MyApp.DecimalAllowingCommas_EditField" %>

<asp:TextBox ID="TextBox1" runat="server" CssClass="droplist" Text='<%# FieldValueEditString %>' Columns="10"></asp:TextBox>

<asp:RequiredFieldValidator runat="server" ID="RequiredFieldValidator1" CssClass="droplist" ControlToValidate="TextBox1" Display="Dynamic" Enabled="false" />
<asp:RegularExpressionValidator runat="server" ID="RegularExpressionValidator1" CssClass="droplist" ControlToValidate="TextBox1" Display="Dynamic" Enabled="false" />
<asp:RangeValidator runat="server" ID="RangeValidator1" CssClass="droplist" ControlToValidate="TextBox1" Type="Double"
Enabled="false" EnableClientScript="true" MinimumValue="0" MaximumValue="100" Display="Dynamic" />
<asp:DynamicValidator runat="server" ID="DynamicValidator1" CssClass="droplist" ControlToValidate="TextBox1" Display="Dynamic" />
<asp:RegularExpressionValidator ID="moneyRegexValidator" runat="server"
ControlToValidate="TextBox1" ErrorMessage="Must be of the format #,###.##."
ValidationExpression="^([1-9]{1}[0-9]{0,2}(\,[0-9]{3})*(\.[0-9]{0,2})?|[1-9]{1}[0-9]{0,}(\.[0-9]{0,2})?|0(\.[0-9]{0,2})?|(\.[0-9]{1,2})?)$"></asp:RegularExpressionValidator>

Here is the code for the .ascx.cs

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Collections.Specialized;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml.Linq;
using System.Web.DynamicData;

namespace MyApp
{
public partial class DecimalAllowingCommas_EditField : System.Web.DynamicData.FieldTemplateUserControl
{
protected void Page_Load(object sender, EventArgs e)
{
TextBox1.ToolTip = Column.Description;

SetUpValidator(RequiredFieldValidator1);
SetUpValidator(RegularExpressionValidator1);
SetUpValidator(RangeValidator1);
SetUpValidator(DynamicValidator1);

// copy it from one of the validators that knows what group we are in. :)
moneyRegexValidator.ValidationGroup = DynamicValidator1.ValidationGroup;

}

protected override void ExtractValues(IOrderedDictionary dictionary)
{
decimal result;
bool successful = Decimal.TryParse(TextBox1.Text, out result);
if (successful)
{
dictionary[Column.Name] = result;
}
}

public override Control DataControl
{
get
{
return TextBox1;
}
}
}
}

No comments: