Reputation: 1249
How to save a TimeOfDay? [duplicate] haven't an answer and this present post it's about a specific problem an not a general question like that post
I'm trying save/submit a Date and a TimeOfDay of a specific DateTime (nullable) variable but when it arrives to my controller its value is always null even user insert other values. How can I solve this?
My visual objective:
My view:
<div style="display:inline-block">
<div class="editor-label">
Initial date:
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.StartDate.Value.Date, new { type = "date" })
@Html.ValidationMessageFor(model => model.StartDate)
</div>
</div>
<div style="display:inline-block">
<div class="editor-label">
Initial hour:
</div>
<div class="editor-field">
@Html.TextBoxFor(model => model.StartDate.Value.TimeOfDay, new { type = "time" })
@Html.ValidationMessageFor(model => model.StartDate)
</div>
</div>
My model:
[DataType(DataType.Date), DisplayFormat(DataFormatString = "{0:dd/MM/yy}", ApplyFormatInEditMode = true)]
public DateTime? StartDate { get; set; }
My model binding (from this link what is great but don't work to nullable dates and I don't know why):
public class DateTimeModelBinder : DefaultModelBinder
{
private Nullable<T> GetA<T>(ModelBindingContext bindingContext, string key) where T : struct
{
if (bindingContext.ValueProvider.ContainsPrefix(bindingContext.ModelName))
{
if (string.IsNullOrEmpty(key)) key = bindingContext.ModelName;
else key = bindingContext.ModelName + "." + key;
}
if (string.IsNullOrEmpty(key)) return null;
ValueProviderResult value;
value = bindingContext.ValueProvider.GetValue(key);
bindingContext.ModelState.SetModelValue(key, value);
if (value == null)
{
return null;
}
Nullable<T> retVal = null;
try
{
retVal = (Nullable<T>)value.ConvertTo(typeof(T));
}
catch (Exception) { }
return retVal;
}
public override object BindModel(
ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
if (bindingContext == null) throw new ArgumentNullException("bindingContext");
// Check for a simple DateTime value with no suffix
DateTime? dateTimeAttempt = GetA<DateTime>(bindingContext, "");
if (dateTimeAttempt != null)
{
return dateTimeAttempt.Value;
}
// Check for separate Date / Time fields
DateTime? dateAttempt = GetA<DateTime>(bindingContext, "Date");
DateTime? timeAttempt = GetA<DateTime>(bindingContext, "TimeOfDay");
//If we got both parts, assemble them!
if (dateAttempt != null && timeAttempt != null)
{
return new DateTime(dateAttempt.Value.Year,
dateAttempt.Value.Month,
dateAttempt.Value.Day,
timeAttempt.Value.Hour,
timeAttempt.Value.Minute,
timeAttempt.Value.Second);
}
//Only got one half? Return as much as we have!
return dateAttempt ?? timeAttempt;
}
}
Upvotes: 0
Views: 1638
Reputation: 1249
The problem was the lack of one ? on the call of my ModelBinder on Global.asax
. So its code changed to:
ModelBinders.Binders.Add(typeof(DateTime?), new Models.DateTimeModelBinder());
and the changes Richard Deeming suggests should be done too:
if (dateAttempt == null && timeAttempt == null)
{
dateAttempt = GetA<DateTime>(bindingContext, "Value.Date");
timeAttempt = GetA<DateTime>(bindingContext, "Value.TimeOfDay");
}
Upvotes: 0
Reputation: 31248
The binder is looking for two post values called StartDate.Date
and StartDate.TimeOfDay
; however, the TextBoxFor
method will have named these controls StartDate.Value.Date
and StartDate.Value.TimeOfDay
instead.
Try adding code to your binder to check for these names:
DateTime? dateAttempt = GetA<DateTime>(bindingContext, "Date");
DateTime? timeAttempt = GetA<DateTime>(bindingContext, "TimeOfDay");
if (dateAttempt == null && timeAttempt == null)
{
dateAttempt = GetA<DateTime>(bindingContext, "Value.Date");
timeAttempt = GetA<DateTime>(bindingContext, "Value.TimeOfDay");
}
Upvotes: 1