2

我们正在将一个大型 WebForms 应用程序转移到 MVC。

在 WebForms 应用程序中,我们有一些可重用的控件 ( .ascx)。例如,在您键入时显示用户名建议的文本框。该控件向页面添加了一些 JS/CSS,具有一些服务器端逻辑和自定义属性(如SelectedUserID)。

在 MVC 应用程序中应该是什么?如何将这些东西封装到 MVC 应用程序中的一个可重用实体中?也许是部分观点?但是您不能<head>从局部视图将 JS/CSS 添加到页面中(最好检查它是否尚未添加)......另外,我如何返回类似于SelectedUserID局部视图中提到的内容?

换个说法——你将如何在 MVC 应用程序中实现这样的控件?

PS。我知道您仍然可以在 MVC 应用程序中使用 .ascx 用户控件,但这似乎是一种“hacky/legacy”方式。什么是“合法”选项?

4

6 回答 6

4

你的问题很广泛。我所有的评论/答案都将在Razor中。在我看来,如果你要切换到 MVC,你不妨使用 Razor。有很多很好的理由来改变,但我想说,对于任何正在迁移的人来说,我的首选,最好的理由是两个;first razor 让我戒掉了一些关于如何使用 webform 进行编程的坏习惯,并且在同一个庄园里,它迫使我重新编写我的代码,而不是尝试复制、粘贴和更改原始代码以在 MVC 中工作。

该控件向页面添加了一些 JS/CSS,具有一些服务器端逻辑和自定义属性。在 MVC 应用程序中应该是什么?

这是一个非常宗教的软件问题。有很多方法可以做到这一点。

因此,我对如何在 MVC 中添加 JS/CSS 持宗教观点。包含服务器端的一种方法是在布局/主模板中创建一个区域。

视图/_ViewStart.cshtml

@{
  Layout = "~/Views/Shared/Layout.cshtml";
}

视图/共享/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)使用 RenderSeion 代码添加任何样式或脚本。

视图/主页/Index.cshtml

@section Styles {
    <link href="/Styles/Home/Index.css" rel="stylesheet" type="text/css" />
}

这非常简单,对于许多简单到中等复杂的网站来说可能是一个很好的解决方案。这对我来说还不够,因为我需要按照您的要求进行操作,并且仅在真正需要时才包含文件。此外,部分视图和模板无法渲染部分,我发现它是一个巨大的 PITA。所以我添加了一些 HtmlHelper 扩展方法。(我只会展示 Javascript 的代码,因为样式表几乎是相同的代码。这些方法不允许重复的 url。

域/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());
    }
}

更新了 Views/Shared/Layout.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()

更新了 Views/Home/Index.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>

另一方面,模板确实需要一个模型才能被渲染。这是因为模板是一种将任何类或结构呈现为编辑模板或显示模板的方法。

/Models/Person.cs

public class Person
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
}

/控制器/HomeController.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 作为可能的包括。我很少包含控制器。

于 2012-05-31T18:26:55.280 回答
4

到目前为止,我发现的最佳解决方案是 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

于 2012-06-03T17:27:19.133 回答
1

我会将 js/css 添加到主布局中,然后编写一个 html 助手来呈现您的自定义控件。

许多在 aspnet mvc 中使用 jquery 的控件都是这样工作的。

在此处查看此控件

于 2012-05-30T22:50:40.877 回答
1

好吧,你不能拥有“自动”包含 css/js 的东西。这是用户必须添加到页面(主/布局或当前页面)的内容。但一般来说,人们会创建一个 Html Helper。不要指望这些是复杂的系统(如 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-应用程序

不要试图将您的 javascript 包含在这些机制中。虽然它可能适用于单个控件,但如果您在页面上有多个控件,您将获得重复的 css/js。

于 2012-05-30T20:27:18.877 回答
0

1) 对于自定义 js/css,您可以使用如下部分:

//视图中的代码

@section someName
{
    ...
}

//布局页面中的代码

@if (IsSectionDefined("someName"))
    {
        @RenderSection("someName")
    }

2)我最好做到以下几点:

  • 使用 Id 属性创建模型 SelectedUser
  • 为此模型创建模板
  • 将 SelectedUser 对象添加到需要它的任何模型
于 2012-05-31T05:53:33.260 回答
0

它们必须用空行与周围的文本隔开。最外面的块元素的开始和结束标签不能缩进。Markdown 不能在 HTML 块中使用。

于 2017-03-16T12:18:42.200 回答