Linking the conflict between the Title property in my model and the View.Title in my view (in MVC)

My model contains a property called Title , and in my Create view I set the page title using ViewBag.Title .

This creates the following problem: the form generated by Html.Editor displays the text from the ViewBag.Title instead of the Title value of the model.

The only workaround I found is to call Html.Editor first and then set View.Title .

Does anyone have a better solution?

Edit 1: I am using MVC 3.

Edit 2: This is my DisplayTemplates/Object.cshtml :

 @model dynamic @using Iconum.VS10CS040.Library.Web.MVC3.Helpers @if (ViewData.TemplateInfo.TemplateDepth > 1) { <span class="editor-object simple">@ViewData.ModelMetadata.SimpleDisplayText</span> } else { foreach (var prop in ViewData.ModelMetadata.Properties.Where( pm => pm.ShowForEdit && !ViewData.TemplateInfo.Visited(pm) && pm.ModelType != typeof(System.Data.EntityState) && !pm.IsComplexType ) ) { if (prop.HideSurroundingHtml) { <text>@Html.Editor(prop.PropertyName)</text> } else { string css = ""; if (prop.Model != null && prop.Model.GetType() != null) { css += " " + prop.Model.GetType().ToString().ToLower().Replace('.', '-'); } if (prop.DataTypeName != null) { css += " " + prop.DataTypeName.ToLower(); } if (prop.IsRequired && prop.ModelType.FullName != "System.Boolean") { css += " required"; } <div class="editor-container @css"> <div class="editor-label"> @if (!String.IsNullOrEmpty(Html.Label(prop.PropertyName).ToHtmlString())) { // Use LabelWithForThatMatchesTheIdOfTheInput instead of Label because of a bug (fixed in MVC 3) @Html.LabelWithForThatMatchesTheIdOfTheInput(prop.PropertyName) } @if (prop.IsRequired && prop.ModelType.FullName != "System.Boolean") { @Html.Raw(" <span class=\"required\">*<span>"); } </div> <div class="editor-field"> @* This the line that causes my problem *@ @Html.Editor(prop.PropertyName) @Html.ValidationMessage(prop.PropertyName) </div> </div> } } //foreach // Loop though all items in the Model with an TemplateHint (UIHint) foreach (var prop in ViewData.ModelMetadata.Properties.Where( pm => pm.ShowForEdit && !ViewData.TemplateInfo.Visited(pm) && pm.ModelType != typeof(System.Data.EntityState) && !pm.IsComplexType && pm.TemplateHint != null && ( pm.TemplateHint == "jWYSIWYG0093" || pm.TemplateHint == "jQueryUIDatepicker" || pm.TemplateHint == "CKEditor" ) ) ) { // TODO: check for duplicate js file includes @Html.Editor(prop.PropertyName, prop.TemplateHint + "-Script") } } 
+8
asp.net-mvc conflict razor model
source share
4 answers

I would recommend using EditorFor instead of Editor .

 Html.EditorFor(x => x.Title) 

instead:

 Html.Editor("Title") 

Thus, not only does the presentation use your presentation model, but it behaves as expected in this case.

Example with RTM (Razor) for ASP.NET MVC 3.0:

Model:

 public class MyViewModel { public string Title { get; set; } } 

Controller:

 public class HomeController : Controller { public ActionResult Index() { ViewBag.Title = "ViewBag title"; ViewData["Title"] = "ViewData title"; var model = new MyViewModel { Title = "Model title" }; return View(model); } } 

View:

 @model AppName.Models.MyViewModel @{ ViewBag.Title = "Home Page"; } @Html.EditorFor(x => x.Title) @{ ViewBag.Title = "Some other title"; } 

So, no matter how much we try to abuse here, the editor template uses the correct model name (this is not the case if we used Html.Editor("Title") ).

+2
source share

As suggested by other answers, using EditorFor instead of Editor seems like a problem. However, using EditorFor requires knowing the type of the model and the type of property at compile time, which is not the case with Object.cshtml .

You can still do this by creating and calling the correct general EditorFor method using reflection. The code for this is really messy, so for this you need to use several extension methods to use.

Use them as in Object.cshtml , where prop is an instance of ModelMetadata , as in the question:

 @Html.DisplayFor(prop) @Html.LabelFor(prop) @Html.EditorFor(prop) @Html.ValidationMessageFor(prop) 

Here are the extension methods:

 using System; using System.Linq.Expressions; using System.Reflection; using System.Web.Mvc; using System.Web.Mvc.Html; using System.Web.Routing; namespace ASP { public static class NonStronglyTypedStronglyTypedHtmlHelpers { public static MvcHtmlString DisplayFor<TModel>(this HtmlHelper<TModel> html, ModelMetadata prop) { return StronglyTypedHelper(html, h => h.DisplayFor, prop); } public static MvcHtmlString EditorFor<TModel>(this HtmlHelper<TModel> html, ModelMetadata prop) { return StronglyTypedHelper(html, h => h.EditorFor, prop); } public static MvcHtmlString LabelFor<TModel>(this HtmlHelper<TModel> html, ModelMetadata prop) { return StronglyTypedHelper(html, h => h.LabelFor, prop); } public static MvcHtmlString ValidationMessageFor<TModel>(this HtmlHelper<TModel> html, ModelMetadata prop) { return StronglyTypedHelper(html, h => h.ValidationMessageFor, prop); } private static MvcHtmlString StronglyTypedHelper(HtmlHelper html, Func<HtmlHelper<object>, GenericHelper<object>> accessMethod, ModelMetadata prop) { var constructedMethod = MakeStronglyTypedHelper(html, accessMethod, prop); var genericPropertyExpression = MakePropertyExpression(prop); var typedHtmlHelper = MakeStronglyTypedHtmlHelper(html, prop.ContainerType); return (MvcHtmlString)constructedMethod.Invoke(null, new object[] { typedHtmlHelper, genericPropertyExpression }); } private static MethodInfo MakeStronglyTypedHelper(HtmlHelper html, Func<HtmlHelper<object>, GenericHelper<object>> accessMethod, ModelMetadata prop) { var objectTypeHelper = new HtmlHelper<object>(html.ViewContext, html.ViewDataContainer, html.RouteCollection); var runMethod = accessMethod(objectTypeHelper); var constructedMehtod = runMethod.Method; var genericHelperDefinition = constructedMehtod.GetGenericMethodDefinition(); return genericHelperDefinition.MakeGenericMethod(prop.ContainerType, prop.ModelType); } private static object MakeStronglyTypedHtmlHelper(HtmlHelper html, Type type) { var genericTypeDefinition = typeof(HtmlHelper<>); var constructedType = genericTypeDefinition.MakeGenericType(type); var constructor = constructedType.GetConstructor(new[] { typeof(ViewContext), typeof(IViewDataContainer), typeof(RouteCollection) }); return constructor.Invoke(new object[] { html.ViewContext, html.ViewDataContainer, html.RouteCollection }); } private static LambdaExpression MakePropertyExpression(ModelMetadata prop) { var propertyInfo = prop.ContainerType.GetProperty(prop.PropertyName); var expressionParameter = Expression.Parameter(prop.ContainerType); var propertyExpression = Expression.MakeMemberAccess(expressionParameter, propertyInfo); return Expression.Lambda(propertyExpression, expressionParameter); } private delegate MvcHtmlString GenericHelper<TModel>(Expression<Func<TModel, object>> expression); } } 
+1
source share

I found a partial solution myself.

Just use:

  @Html.EditorForModel() 

instead:

  @foreach (var property in Model.GetMetadata().Properties) { <div class="editor-label"> @Html.Label(property.PropertyName) </div> <div class="editor-field"> @Html.Editor(property.PropertyName) @Html.ValidationMessage(property.PropertyName) </div> } 

The Html.EditorForModel () method returns the same results, but without the described problem.

-one
source share

I solve the same problem. Use this syntax instead of Html.Editor

 @(Html.EditorFor(p => property.Model)) 
-one
source share

Source: https://habr.com/ru/post/649895/


All Articles