Thank you very much Brian. You put me on the right track with the DummyControl class. My real world user control needed to have about 12 inputs on it, so having a control name for each was a bit messy. Ultimately I was looking for the HtmlFieldPrefix property to solve the unique input IDs problem. Here's the simple example solution I ended up with:
public class Person
{
public string Name { get; set; }
public DateTimeControl DateOfBirth { get; set; }
public DateTimeControl DateOfDeath { get; set; }
}
public class DateTimeControl
{
[Display(Name = "Day: ")]
public string Day { get; set; }
[Display(Name = "Month: ")]
public string Month { get; set; }
[Display(Name = "Year: ")]
public string Year { get; set; }
}
And the partial view as follows:
@model Models.DateTimeControl
<div class="form-group">
@Html.LabelFor(m => m.Day)
@Html.EditorFor(m => m.Day, new { @class = "form-control" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.Month)
@Html.EditorFor(m => m.Month, new { @class = "form-control" })
</div>
<div class="form-group">
@Html.LabelFor(m => m.Year)
@Html.EditorFor(m => m.Year, new { @class = "form-control" })
</div>
Then I can use the partial view multiple times in the same view, overcoming the unique IDs with the HtmlFieldPrefix property.
<div class="form-group">
@Html.LabelFor(m => m.Name)
@Html.EditorFor(m => m.Name, new { @class = "form-control" })
</div>
@Html.Partial("_DateTimeInput", Model.DateOfBirth, new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "DateOfBirth" } })
@Html.Partial("_DateTimeInput", Model.DateOfDeath, new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "DateOfDeath" } })
So that the generated HTML is:
<div class="form-group">
<label for="DateOfBirth_Day">Day: </label>
<input class="text-box single-line" id="DateOfBirth_Day" name="DateOfBirth.Day" type="text" value="" />
</div>
<div class="form-group">
<label for="DateOfBirth_Month">Month: </label>
<input class="text-box single-line" id="DateOfBirth_Month" name="DateOfBirth.Month" type="text" value="" />
</div>
<div class="form-group">
<label for="DateOfBirth_Year">Year: </label>
<input class="text-box single-line" id="DateOfBirth_Year" name="DateOfBirth.Year" type="text" value="" />
</div>
<div class="form-group">
<label for="DateOfDeath_Day">Day: </label>
<input class="text-box single-line" id="DateOfDeath_Day" name="DateOfDeath.Day" type="text" value="" />
</div>
<div class="form-group">
<label for="DateOfDeath_Month">Month: </label>
<input class="text-box single-line" id="DateOfDeath_Month" name="DateOfDeath.Month" type="text" value="" />
</div>
<div class="form-group">
<label for="DateOfDeath_Year">Year: </label>
<input class="text-box single-line" id="DateOfDeath_Year" name="DateOfDeath.Year" type="text" value="" />
</div>
When mixed with additional inputs in the outer View, the entire model is populated and sent to the controller as expected when the user hits the submit button.