I\'ve just updated my Visual Studio 2017 ASP.NET MVC 5 application from Bootstrap v3 to v4. I\'m finding when I add a new edit partial view using scaffolding, it is still us
An update is not yet available, however to support the edit view scaffolding with Bootstrap 4 in Visual Studio 2017, You have to edit the file Edit.cs.t4 in "%ProgramFiles%\Microsoft Visual Studio\2017\Community\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates\MvcView"
<#@ template language="C#" HostSpecific="True" #>
<#@ output extension=".cshtml" #>
<#@ include file="Imports.include.t4" #>
@model <#= ViewDataTypeName #>
<#
// "form-control" attribute is only supported for all EditorFor() in System.Web.Mvc 5.1.0.0 or later versions, except for checkbox, which uses a div in Bootstrap
string boolType = "System.Boolean";
Version requiredMvcVersion = new Version("5.1.0.0");
bool isControlHtmlAttributesSupported = MvcVersion >= requiredMvcVersion;
// The following chained if-statement outputs the file header code and markup for a partial view, a view using a layout page, or a regular view.
if(IsPartialView) {
#>
<#
} else if(IsLayoutPageSelected) {
#>
@{
ViewBag.Title = "<#= ViewName#>";
<#
if (!String.IsNullOrEmpty(LayoutPageFile)) {
#>
Layout = "<#= LayoutPageFile#>";
<#
}
#>
}
<h2><#= ViewName#></h2>
<#
} else {
#>
@{
Layout = null;
}
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title><#= ViewName #></title>
</head>
<body>
<#
PushIndent(" ");
}
#>
<#
if (ReferenceScriptLibraries) {
#>
<#
if (!IsLayoutPageSelected && IsBundleConfigPresent) {
#>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/jqueryval")
<#
}
#>
<#
else if (!IsLayoutPageSelected) {
#>
<script src="~/Scripts/jquery-<#= JQueryVersion #>.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<#
}
#>
<#
}
#>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<h4><#= ViewDataTypeShortName #></h4>
<hr />
<#
if (isControlHtmlAttributesSupported) {
#>
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<#
} else {
#>
@Html.ValidationSummary(true)
<#
}
#>
<#
foreach (PropertyMetadata property in ModelMetadata.Properties) {
if (property.Scaffold && !property.IsAssociation) {
if (property.IsPrimaryKey) {
#>
@Html.HiddenFor(model => model.<#= property.PropertyName #>)
<#
} else if (!property.IsReadOnly) {
bool isCheckbox = property.TypeName.Equals(boolType);
#>
<div class="form-group">
<#
if (property.IsForeignKey) {
#>
@Html.LabelFor(model => model.<#= property.PropertyName #>, "<#= GetAssociationName(property) #>", htmlAttributes: new { @class = "col-form-label col-lg-2" })
<#
} else if (!isCheckbox) {
#>
@Html.LabelFor(model => model.<#= property.PropertyName #>, htmlAttributes: new { @class = "col-form-label col-lg-2" })
<#
}
#>
<div class="col-lg-10">
<#
if (property.IsForeignKey) {
#>
<#
if (isControlHtmlAttributesSupported) {
#>
@Html.DropDownList("<#= property.PropertyName #>", null, htmlAttributes: new { @class = "form-control" })
<#
} else {
#>
@Html.DropDownList("<#= property.PropertyName #>", String.Empty)
<#
}
#>
<#
} else if (isControlHtmlAttributesSupported) {
if (isCheckbox) {
#>
<div class="custom-control custom-checkbox">
<#
PushIndent(" ");
#>
@Html.EditorFor(model => model.<#= property.PropertyName #>, new { htmlAttributes = new { @class = "custom-control-input" } })
@Html.LabelFor(model => model.<#= property.PropertyName #>, htmlAttributes: new { @class = "custom-control-label" })
<#
} else if (property.IsEnum && !property.IsEnumFlags) {
#>
@Html.EnumDropDownListFor(model => model.<#= property.PropertyName #>, htmlAttributes: new { @class = "form-control" })
<#
} else {
#>
@Html.EditorFor(model => model.<#= property.PropertyName #>, new { htmlAttributes = new { @class = "form-control" } })
<#
}
} else {
#>
@Html.EditorFor(model => model.<#= property.PropertyName #>)
<#
}
#>
<#
if (isControlHtmlAttributesSupported) {
#>
@Html.ValidationMessageFor(model => model.<#= property.PropertyName #>, "", new { @class = "text-danger" })
<#
} else {
#>
@Html.ValidationMessageFor(model => model.<#= property.PropertyName #>)
<#
}
#>
<#
if (isCheckbox && isControlHtmlAttributesSupported) {
PopIndent();
#>
</div>
<#
}
#>
</div>
</div>
<#
}
}
}
#>
<div class="form-group">
<div class="col-lg-10">
<input type="submit" value="Save" class="btn btn-primary">
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
<#
if(IsLayoutPageSelected && ReferenceScriptLibraries && IsBundleConfigPresent) {
#>
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
<#
}
#>
<#
else if(IsLayoutPageSelected && ReferenceScriptLibraries) {
#>
<script src="~/Scripts/jquery-<#= JQueryVersion #>.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<#
}
#>
<#
// The following code closes the tag used in the case of a view using a layout page and the body and html tags in the case of a regular view page
#>
<#
if(!IsPartialView && !IsLayoutPageSelected) {
ClearIndent();
#>
</body>
</html>
<#
}
#>
<#@ include file="ModelMetadataFunctions.cs.include.t4" #>
To fix/update the ASP .NET MVC 5 project navbar to Bootstrap 4 you have to update your code manually as follows:
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
@Html.ActionLink("Application name", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target=".navbar-collapse" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav mr-auto">
<li class="nav-item">@Html.ActionLink("Home", "Index", "Home", null, new { @class = "nav-link" })</li>
<li class="nav-item">@Html.ActionLink("About", "About", "Home", null, new { @class = "nav-link" })</li>
<li class="nav-item">@Html.ActionLink("Contact", "Contact", "Home", null, new { @class = "nav-link" })</li>
</ul>
@Html.Partial("_LoginPartial")
</div>
</div>
</nav>
Then if you don’t use the Login partial, you can remove it. Otherwise, change the _LoginPartial.cshtml to:
@using Microsoft.AspNet.Identity
@if (Request.IsAuthenticated)
{
using (Html.BeginForm("LogOff", "Account", FormMethod.Post, new { id = "logoutForm" }))
{
@Html.AntiForgeryToken()
<ul class="nav navbar-nav">
<li class="nav-item">
@Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage", @class = "nav-link" })
</li>
<li class="nav-item"><a class="nav-link" href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
</ul>
}
}
else
{
<ul class="nav navbar-nav">
<li class="nav-item">@Html.ActionLink("Register", "Register", "Account", routeValues: null, htmlAttributes: new { id = "registerLink", @class = "nav-link" })</li>
<li class="nav-item">@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink", @class = "nav-link" })</li>
</ul>
}
And last just remove the next lines from Content/Site.css:
/*delete this*/
body {
padding-top: 50px;
padding-bottom: 20px;
}
The templates used by the scaffolding engine in VS are fixed. They are located in your VS install dir (e.g. %programfiles%\Microsoft Visual Studio\2017\Community\Common7\IDE\Extensions\Microsoft\Web\Mvc\Scaffolding\Templates\MvcView).
So the Bootstrap 3 classes are fixed in the T4-files provided by MS (current standard is BS3 which is added by default currently when creating a new MVC web project). Just have a look at "Edit.cs.t4" in the dir mentioned above. You will find deprecated BS3 classes like "btn-default" (which is btn-secondary in BS4) in there.
You can create your own custom T4-templates if you like. The MS ref for this task would be: https://docs.microsoft.com/en-us/visualstudio/modeling/code-generation-and-t4-text-templates