I’m working on an application at the moment that replicates a spreadsheet like table. I’ve been doing it all with ASP.NET model binding and a combination of ajax and a form POST. I’ve run into some issues where I think I might be better off creating a custom model binder.
Here’s my application:

What we have there are stages of a project, and then a bunch of columns corresponding to each month with the predicted cashflows.
There is a button to the right of that image that lets you add an extra month column, and you can add a stage using the add stage button. Those two are done with AJAX, and then when you submit the form I want it to save all changes in one go via a POST.
I’ve managed to manoeuvre my way around using HTML helpers, view models and default model binding to get it working with adding columns:
In my main view, I have this to generate the rows/columns in the TBODY
<tbody>
@for (int stageIndex = 0; stageIndex < Model.Stages.Count; stageIndex++)
{
@Html.EditorFor(x => x.Stages[stageIndex])
}
</tbody>
<tfoot>
I have a partial view for CashflowStageViewModel which currently looks like:
@model BWInvoicing.Ui.Models.CashflowStageViewModel
<tr class="stageRow">
@Html.HiddenFor(x => x.Stage)
<td class="stage">
<div class="stageWrapper">
<div>
@Model.Stage
</div>
<div class="stageOptions">
<img class="deleteRowButton" src="../../../Content/Images/delete.png" id=@Model.Stage />
</div>
</div>
</td>
<td>
@Html.TextBoxFor(x => x.Amount, new { @Class = "totalFee emTotal", CashflowStage = Model.Stage })
</td>
<td>
@Html.TextBox("summation", 0, new { @Class = "emTotal summation", CashflowStage = Model.Stage, @readonly = "true" })
</td>
@for (int i = 0; i < Model.Months.Count; i++)
{
<td>
@Html.HiddenFor(x => Model.Months[i].Date)
@Html.TextBoxFor(x => Model.Months[i].Amount, new { @Class = "prediction", CashflowStage = Model.Stage })
</td>
}
<td class="stageHeadingEnd">
@Model.Stage
</td>
</tr>
The model binding works by creating IDs and name’s that look like this:
id="Stages_5__Months_4__Amount" name="Stages[5].Months[4].Amount"
This causes some issues as I can add/delete rows between the time that these are generated and the time they are sent back to the server. I always try to keep using the default binding, but now it’s holding me back so I think it’s time I just created a custom model binder, rather than try dirty hacks to keep the indexes right.
My questions are these:
- Do you agree a custom model binder is the way to go? or is there an easy trick I’m missing
- What do you recommend I do in my custom model binder in terms of the names and ID’s of my fields and cells in order to read it back in the http post. Is there some sort of guidance on how you should try and name them? Or should I just do string splitting?
By this I mean, for each cell should I have a hidden with name of STAGENAME_DATE and value of whatever they enter in the text box? and then I can have a model binder split those strings up to split the stage name and the date, parse them, and assign a value to the stage on that certain date? Or is there a more appropriate way of doing it?
I ended up reading about how you can use your own arbritrary indexes here:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
As a result I updated my viewmodel output to be following:
I’m not very happy with how messy the concatenation is, but it works pretty well.