可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I am trying to format a date rendered by ASP.Net MVC's TextBoxFor using the value of a strongly typed view. The date is nullable so if it is null I want to see a blank value, otherwise I want to see it in the format MM/dd/yyyy.
<%= Html.TextBoxFor(model => model.BirthDate, new { style = "width: 75px;" })%>
Thanks,
Paul Speranza
回答1:
You can keep the strong typing by using a custom editor template and Html.EditorFor()
instead of Html.TextBoxFor()
.
Create a new EditorTemplates folder in your /Views/Shared folder and add a new MVC 2 View User Control named DateTime.ascx. Add the following
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<System.DateTime?>" %>
<%= Html.TextBox("", (Model.HasValue ? Model.Value.ToString("MM/dd/yyyy") : string.Empty)) %>
Then in your view use
<%= Html.EditorFor(model => model.BirthDate)%></p>
Don't worry about the "", the naming will still work correctly.
If you are displaying the DateTime in a different culture format to the default application culture then you will need to change the culture information or alternatively create a custom model binder in order for the model binding to work when posting back the DateTime.
回答2:
MVC4 http://msdn.microsoft.com/en-us/library/hh833694.aspx
@Html.TextBoxFor(model => model.YOUR_DATE, "{0:MM/dd/yyyy}")
回答3:
First, add this extension for getting property path:
public static string GetPropertyPath<TEntity, TProperty>(Expression<Func<TEntity, TProperty>> property)
{
Match match = Regex.Match(property.ToString(), @"^[^\.]+\.([^\(\)]+)$");
return match.Groups[1].Value;
}
Than add this extensions for HtmlHalper:
public static MvcHtmlString DateBoxFor<TEntity>(
this HtmlHelper helper,
TEntity model,
Expression<Func<TEntity, DateTime?>> property,
object htmlAttributes)
{
DateTime? date = property.Compile().Invoke(model);
// Here you can format value as you wish
var value = date.HasValue ? date.Value.ToShortDateString() : string.Empty;
var name = ExpressionParseHelper.GetPropertyPath(property);
return helper.TextBox(name, value, htmlAttributes);
}
Also you should add this jQuery code:
$(function() {
$("input.datebox").datepicker();
});
datepicker is a jQuery plugin.
And now you can use it:
<%= Html.DateBoxFor(Model, (x => x.Entity.SomeDate), new { @class = "datebox" }) %>
回答4:
It's a dirty hack, but it seems to work.
<%= Html.TextBoxFor(model => model.SomeDate,
new Dictionary<string, object> { { "Value", Model.SomeDate.ToShortDateString() } })%>
You get the model binding, and are able to override the HTML "value" property of the text field with a formatted string.
回答5:
You can consider the following sample of TextBoxFor Extension method for datetime data:
public static MvcHtmlString CalenderTextBoxFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
{
Func<TModel, TProperty> deleg = expression.Compile();
var result = deleg(htmlHelper.ViewData.Model);
string value = null;
if (result.ToString() == DateTime.MinValue.ToString())
value = string.Empty;
else
value = string.Format("{0:M-dd-yyyy}", result);
return htmlHelper.TextBoxFor(expression, new { @class = "datepicker text", Value = value });
}
回答6:
Just name it what it is looking for. Like:
Html.TextBox("Person.StartTime",Person.StartTime.ToShortDateString());
When it returns to the controller, your model will have the value bounded.
回答7:
Have you tried to force the culture of your current thread application? You can override it in the web.config using this line (in the tag) :
<!-- Default resource files are set here. The culture will also change date format, decimal, etc... -->
<globalization enableClientBasedCulture="false" culture="en-US" uiCulture="en-US"/>
回答8:
A simple solution is to not use the strongly typed helper.
<%= Html.TextBox("StartDate", string.Format("{0:d}", Model.StartDate)) %>
回答9:
I use some custom helpers and have used them successfully in MVC 2 and 3 (code also on Snipplr). The helpers have some css logic thrown in as I use the jQuery-ui datepicker, but that can easily be removed.
public static MvcHtmlString DateTextBoxFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, string formatString, object htmlAttributes)
{
var metadata = ModelMetadata.FromLambdaExpression(expression, helper.ViewData);
string format = String.IsNullOrEmpty(formatString) ? "M/d/yyyy" : formatString;
DateTime date = metadata.Model == null ? new DateTime() : DateTime.Parse(metadata.Model.ToString());
string value = date == new DateTime() ? String.Empty : date.ToString(format);
RouteValueDictionary attributes = new RouteValueDictionary(htmlAttributes);
string datePickerClass = "date-selector";
if (attributes.ContainsKey("class"))
{
string cssClass = attributes["class"].ToString();
attributes["class"] = cssClass.Insert(cssClass.Length, " " + datePickerClass);
}
else
{
attributes["class"] = datePickerClass;
}
return helper.TextBox(ExpressionHelper.GetExpressionText(expression), value, attributes);
}
public static MvcHtmlString DateTextBoxFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression)
{
return DateTextBoxFor<TModel, TValue>(helper, expression, String.Empty, null);
}
public static MvcHtmlString DateTextBoxFor<TModel, TValue>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, string formatString)
{
return DateTextBoxFor<TModel, TValue>(helper, expression, formatString, null);
}
回答10:
Seriously, why should the view have to do this?
Map your core model which has the date time object to your mvc view model.
//core model
public class Person
{
public DateTime? BirthDate { get; set;}
}
//view model
public class PersonForm
{
public string BirthDate { get; set; }
}
So mapping might look like:
public interface IDomainToViewMapper<TModel, TViewModel>
{
/// <summary>
/// Use an automapper or custom implementation to map domain model to presentation model.
/// </summary>
/// <param name="source">domain model</param>
/// <returns>presentation model</returns>
TViewModel MapDomainToView(TModel source);
}
public interface IPersonMapper : IDomainToViewMapper<Person, PersonForm>
{
}
public class PersonMapper : IPersonMapper
{
#region IDomainToViewMapper<Person,PersonForm> Members
public PersonForm MapDomainToView(Person source)
{
PersonForm p = new PersonForm();
if (source.BirthDate.HasValue)
{
p.BirthDate = source.BirthDate.Value.ToShortDateString();
}
return p;
}
#endregion
}
And your controller action might look like:
public ActionResult Index()
{
Person person = //get person;
var personForm = _personMapper.MapDomainToView(person);
return View(personForm)
}
You won't have to change your view example at all then.
From Chapter 2, MVC 2 in Action (Manning)
public class CustomerSummary
{
public string Name { get; set; }
public bool Active { get; set; }
public string ServiceLevel { get; set; }
public string OrderCount { get; set;}
public string MostRecentOrderDate { get; set; }
}
This model is intentionally simple; it consists mostly of strings. That’s what we’re representing,
after all: text on a page. The logic that displays the data in this object will be
straightforward; the view will only output it. The presentation model is designed to
minimize decision making in the view.
回答11:
Have you tried just passing in the date format that you'd like?
Html.TextBoxFor(model => model.BirthDate.ToString("MM/dd/yyyy"),
new { style = "width: 75px;" })