我们正在将一个大型WebForms应用程序转移到MVC。
在WebForms应用程序中,我们有一些可重用的控件(.ascx
)。例如,在您键入时显示用户名建议的文本框。该控件向页面添加一些 JS/CSS,具有一些服务器端逻辑和自定义属性(如 SelectedUserID
)。
MVC 应用程序中应该是什么?如何将这些内容封装到 MVC 应用中的一个可重用实体中?也许是部分观点?但是你不能从部分视图将 JS/CSS 添加到页面的<head>
(最好检查它是否尚未添加)......另外,如何在部分视图中返回类似于上述SelectedUserID
的内容?
换个问题 - 如何在 MVC 应用中实现这样的控件?
附言。我知道您仍然可以在 MVC 应用程序中使用 .ascx 用户控件,但这似乎是一种"黑客/遗留"的方式。什么是"合法"选项?
你的问题很宽泛。 我所有的评论/答案都将在 Razor 中。 在我看来,如果你要切换到MVC,你不妨使用Razor。 有很多很好的理由来转换,但我想说我的首选是任何正在迁移的人,最好的理由是双重的;首先,Razor 允许我放弃一些关于编程如何使用 Web 表单的坏习惯,在同一个庄园里,它迫使我重写我的代码,而不是尝试复制和粘贴并更改原始代码以在 MVC 中工作。
该控件向页面添加一些 JS/CSS,具有一些服务器端逻辑和自定义属性。 MVC 应用程序中应该是什么?
这是一个非常宗教的软件问题。有很多方法可以做到这一点。
因此,关于如何在MVC中添加JS/CSS的宗教观点。 包含服务器端的一种方法是在布局/主模板中创建区域。
Views/_ViewStart.cshtml
@{
Layout = "~/Views/Shared/Layout.cshtml";
}
Views/Shared/Layout.cshtml
<!doctype html>
<head>
<link href="/Styles/Global.css" rel="stylesheet" type="text/css" />
@RenderSection("Styles", required: false)
<script src="/Scripts/Global.js" type="text/javascript"></script>
@RenderSection("Scritps", required: false)
这将允许每个视图选择性地(因为required=false
)使用RenderSecion代码添加任何样式或脚本。
Views/Home/Index.cshtml
@section Styles {
<link href="/Styles/Home/Index.css" rel="stylesheet" type="text/css" />
}
这非常简单,对于许多简单到中等复杂的网站来说可能是一个很好的解决方案。 这对我来说还不够,因为我需要按照您的要求进行操作,并且仅在真正需要时才包含文件。 此外,部分视图和模板无法呈现部分,我发现这是一个巨大的PITA。 所以我添加了一些 HtmlHelper 扩展方法。 (我只展示Javascript的代码,因为样式表几乎是相同的代码。 这些方法不允许重复网址。
Domain/HtmlHelperExtensions.cshtml
public static class HtmlHelperExtensions
{
private const string _JSViewDataName = "RenderJavaScript";
private const string _StyleViewDataName = "RenderStyle";
public static void AddJavaScript(this HtmlHelper HtmlHelper, string ScriptURL)
{
List<string> scriptList = HtmlHelper.ViewContext.HttpContext.Items[HtmlHelperExtensions._JSViewDataName] as List<string>;
if (scriptList != null)
{
if (!scriptList.Contains(ScriptURL))
{
scriptList.Add(ScriptURL);
}
}
else
{
scriptList = new List<string>();
scriptList.Add(ScriptURL);
HtmlHelper.ViewContext.HttpContext.Items.Add(HtmlHelperExtensions._JSViewDataName, scriptList);
}
}
public static MvcHtmlString RenderJavaScripts(this HtmlHelper HtmlHelper)
{
StringBuilder result = new StringBuilder();
List<string> scriptList = HtmlHelper.ViewContext.HttpContext.Items[HtmlHelperExtensions._JSViewDataName] as List<string>;
if (scriptList != null)
{
foreach (string script in scriptList)
{
result.AppendLine(string.Format("<script type="text/javascript" src="{0}"></script>", script));
}
}
return MvcHtmlString.Create(result.ToString());
}
}
更新的视图/共享/布局.cshtml
<!doctype html>
<head>
<link href="/Styles/Global.css" rel="stylesheet" type="text/css" />
@Html.RenderStyleSheets()
<script src="/Scripts/Global.js" type="text/javascript"></script>
@Html.RenderJavascripts()
更新的视图/主页/索引.cshtml
@Html.AddStyleSheet("/Styles/Home/Index.css")
关于你的下一个问题...
如何将这些内容封装到 MVC 应用中的一个可重用实体中?也许是部分观点?
Razor 同时支持部分视图和模板。 尽管从技术上讲,每个都可以做什么有很大的重叠,但每个设计方式都存在局限性,以便程序员在需要时利用每个。
分部视图不需要模型/类即可呈现。这是一个完全有效的部分视图:
/views/home/index.cshtml
@Html.Partial("Partial-Menu")
/views/shared/Partial-Menu.cshtml
<div id="menu">
<a href="/">Home</a>
<a href="/Home/About">About Us</a>
</div>
另一方面的模板确实需要一个模型才能渲染。 这是因为模板是一种将任何类或结构呈现为编辑模板或显示模板的方法。
/模特/人.cs
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
/控制器/家庭控制器.cs
public ActionResult Index()
{
Person model = new Person();
model.FirstName = "Jon";
model.LastName = "Doe";
return this.View(model);
}
/views/home/index.cshtml
@model Project1.Models.Person
@Html.DisplayModel()
@Html.EditforModel()
/views/Shared/DisplayTemplates/Person.cshtml
@model Project1.Models.Person
<div>@Html.LabelFor(x => x.FirstName) @Html.DisplayFor(x => x.FirstName)</div>
<div>@Html.LabelFor(x => x.LastName) @Html.DisplayFor(x => x.LastName)</div>
/views/Shared/EditorTemplates/Person.cshtml
@model Project1.Models.Person
<div>@Html.LabelFor(x => x.FirstName) @Html.EditorFor(x => x.FirstName)</div>
<div>@Html.LabelFor(x => x.LastName) @Html.EditrorFor(x => x.LastName)</div>
在我看来,任何可能变成数据输入表单的模型都应该是一个模板。 这是我更喜欢封装模型的方式。 使用前面提供的扩展方法,我的分部视图和模板都可以根据需要加载包含(目前只有我的一个模型实际上需要使用它)。
我的偏好是每页最多呈现三个包含(每个Javascript和样式)。 我基本上有一个 Global.css/js、一个控制器 Home.css/js 和一个页面 Index.css/js 作为可能的包含。 我很少有控制器包含。
到目前为止,我找到的最佳解决方案是 Razor 声明式助手。它们非常合适。
@helper UserTextBox() {
<input type="text" />
<!--my own helper that registers scripts-->
@Html.AddJS("../js/myscript.js")
}
相关问题:Razor:声明性 HTML 帮助程序
相关说明:不能在声明性帮助程序中使用@Html帮助程序,但有一个解决方法:https://stackoverflow.com/a/5557503/56621
好吧,你不能拥有"自动"包含css/js的东西。 这是用户必须添加到页面(母版/布局或当前页面)的内容。 但一般来说,人们会创建一个 Html 助手。 不要指望这些是复杂的系统(比如 asp.net 天的巨大网格),但你可以用它们做很多事情。
是的,对于简单的事情,部分页面可能更容易。 更简单的可能是编辑器或显示模板。
然而,一般来说,现在大多数MVC的"控件"都是基于jQuery的。
此处提供简短视频:http://www.asp.net/mvc/videos/mvc-2/how-do-i/how-do-i-create-a-custom-html-helper-for-an-mvc-application
不要试图将你的javascript包含在这些机制中。 虽然它可能适用于单个控件,但如果页面上有多个控件,您将获得重复的 css/js。
我会将 js/css 添加到主布局中,然后编写一个 html 助手来呈现您的自定义控件。
在aspnet mvc中使用jquery的许多控件都是这样工作的。
在此处查看此控件
1)对于自定义的JS/CSS,你可以使用这样的部分:
视图中的代码
@section someName
{
...
}
布局页面中的代码
@if (IsSectionDefined("someName"))
{
@RenderSection("someName")
}
2)我最好做到以下几点:
- 创建模型 具有 ID 属性的选定用户
- 为此模型创建模板
- 将 SelectedUser 对象添加到任何需要它的模型
它们必须用空行与周围的文本分隔。最外层块元素的开始和结束标记不得缩进。Markdown 不能在 HTML 块中使用。