用户控件的MVC替代品

时间:2012-05-30 20:14:54

标签: asp.net-mvc

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

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

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

重新解释这个问题 - 如何在MVC应用中实现这样的控制?

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

6 个答案:

答案 0 :(得分:4)

你的问题非常广泛。我的所有评论/答案都将在Razor中。在我看来,如果你要转向MVC,你也可以使用Razor。有很多很好的理由可以转换,但是对于任何正在迁移的人我都会说我的首选,最好的理由是两倍;第一个剃刀允许我放弃一些关于编程如何与webforms一起工作的坏习惯,并且在同一庄园中它迫使我重新编写代码而不是尝试复制和粘贴并更改原始代码以在MVC中工作。

  

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

这是一个非常religious software的问题。有很多方法可以做到。

关于如何在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)使用RenderSecion代码添加任何样式或脚本。

<强>查看/主页/ 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());
    }
}

更新了视图/共享/ 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()

更新了视图/主页/ Index.cshtml

@Html.AddStyleSheet("/Styles/Home/Index.css")

到你的下一个问题......

  

如何将这些内容封装到MVC应用程序中的一个可重用实体中?也许局部观点?

Razor支持部分视图和模板。虽然从技术上讲,每种方法都有很大的重叠,但每种方法的设计都存在局限性,允许程序员在需要时利用每种方法。

部分视图需要Model / Class才能呈现。这是一个完全有效的局部视图:

<强> /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; }
}

<强> /Controllers/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。我很少有控制器包含。

答案 1 :(得分:4)

到目前为止,我发现的最佳解决方案是Razor声明性助手。它们很合适。

@helper UserTextBox() {
    <input type="text" />

    <!--my own helper that registers scripts-->
    @Html.AddJS("../js/myscript.js") 
}

相关问题:Razor: Declarative HTML helpers

相关说明:您不能在声明性帮助器中使用@Html助手,但有一种解决方法:https://stackoverflow.com/a/5557503/56621

答案 2 :(得分: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-application

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

答案 3 :(得分:1)

我会将js / css添加到主布局,然后编写一个html帮助器来渲染自定义控件。

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

看看这个控件here

答案 4 :(得分:0)

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

//视图中的代码

@section someName
{
    ...
}

//布局页面中的代码

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

2)我最好做以下事情:

  • 使用Id属性创建模型SelectedUser
  • 为此模型创建模板
  • 将SelectedUser对象添加到需要它的任何模型

答案 5 :(得分:0)

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