ASP.NET MVC custom binder for currency

June 24, 2009 on 8:05 am | In ASP.NET MVC | 1 Comment

I can imagine that’s quite common problem. You have a double (or better decimal) value that you want to show formatted as a currency field. Lets assume we are storing the price data in an object like this:

public class TestModel
{
    public double NumberField
    {
        get;
        set;
    }

    public double CurrencyField
    {
        get;
        set;
    }
}

The MVC view is strongly typed with this TestModel. And the view model value is formatted like this:

<%=Html.TextBox(“NumberField”, Model.NumberField)%>

<%=Html.TextBox(“CurrencyField”, Model.CurrencyField.ToString(“c”))%>

If you set the current culture to German-Swiss, for example in (base)controller like that:

protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
    base.Initialize(requestContext);

    string culture = "de-CH";

    CultureInfo ci = CultureInfo.GetCultureInfo(culture);

    Thread.CurrentThread.CurrentCulture = ci;
    Thread.CurrentThread.CurrentUICulture = ci;
}

Done so we will get a text boxes looking like this:

image

What will happen if you use a default binder to get this value? The default binder will try to parse the string as a double value and get an ModelState error. The string does not represent a double value.

To deal with this issue we have to write our own model binder. This can be done by implementing the IModelBinder. But I don’t want to reimplement this how DefaultModelBinder reads other values than my currency doubles. So I though I will set a special attribute to the “special” properties. Something like this:

[AttributeUsage(AttributeTargets.Property)]
public class CurrencyAttribute : Attribute
{
}

And my object:

public class TestModel
{
    public double NumberField
    {
        get;
        set;
    }

    [Currency]
    public double CurrencyField
    {
        get;
        set;
    }
}

And now we can overload the DefaultModelBinder and implement our TestModelBinder like this:

public class TestModelBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext,
            ModelBindingContext bindingContext)
        {
            object bindingObject = base.BindModel(controllerContext,
                bindingContext);

            foreach (System.Reflection.PropertyInfo propInfo
                in bindingObject.GetType().GetProperties())
            {
                object[] attributes =
                    propInfo.GetCustomAttributes(typeof(CurrencyAttribute), false);

                foreach (object attribute in attributes)
                {
                    CurrencyAttribute currAtt = attribute as CurrencyAttribute;

                    if (currAtt != null)
                    {
                        bindingContext.ModelState[propInfo.Name].Errors.Clear();

                        string attempted =
                            bindingContext.ValueProvider[propInfo.Name].AttemptedValue;
                        CultureInfo ci =
                            bindingContext.ValueProvider[propInfo.Name].Culture;

                        propInfo.SetValue(
                            bindingObject,
                            double.Parse(attempted, NumberStyles.Currency, ci),
                            null);

                    }
                }
            }

            return bindingObject;
        }
    }

And now we have to set the attribute to our object to tell MVC that it has to use your binder.

[ModelBinder(typeof(TestModelBinder))]
public class TestModel
{
    public double NumberField
    {
        get;
        set;
    }

    [Currency]
    public double CurrencyField
    {
        get;
        set;
    }
}

Done! Although there are a view issues with this solution (if you are using Entity Framework you cannot set custom attributes, and in the binder above you will have to implement checking if the field is present on the view), but you get the general idea!

Easiest way to have 2 submit button in one html form

June 12, 2009 on 4:41 pm | In DHTML, JavaScript | No Comments

Here is the easiest way to have two (or more) submit buttons in one html form and to make them “do” something else. It is very helpful if you are planning to implement a toolbar like behavior. Example is from ASP.NET MVC but it does not matter. Since it uses JavaScript to dynamically change the action attribute of a form tag, it can be used everywhere. Here it is:

    <h2><%= Html.Encode(ViewData["Message"]) %></h2>

    <script language="javascript" type="text/javascript">
        function ChangeFormAction(sender, url) {
            sender.form.action = url;
        }
    </script>

    <form method="post">
        <input id="text" name="text" type="text" value="Hello from Action" />
        <br />
        <input type="submit" value="Go to action 1"
            onclick="ChangeFormAction(this, '/Home/Action1')" />
        <input type="submit" value="Go to action 2"
            onclick="ChangeFormAction(this, '/Home/Action2')" />
    </form>

And the actions that responds to this form are here:

public class HomeController : Controller
{
    public ActionResult Action1(string text)
    {
        ViewData["Message"] = text + "1";

        return View("Index");
    }

    public ActionResult Action2(string text)
    {
        ViewData["Message"] = text + "2";

        return View("Index");
    }
}
Nice!

Powered by WordPress with Pool theme design by Borja Fernandez.
Text © Marcin Kawalerowicz. Hosting CODEFUSION.