【问题标题】:What is the MVC equivalent of Find Control?Find Control 的 MVC 等价物是什么?
【发布时间】:2015-08-14 15:45:11
【问题描述】:

在 ASP.NET Web 表单中,可以从母版页修改页面控件。例如,在页面“/Sample”上,我可以通过执行以下操作将 TextBox1 设置为只读。

//Site.master.cs
protected void Page_Load(object sender, EventArgs e)
{
    if (Request.Path.ToUpper().Contains("/SAMPLE"))
    {
        TextBox TB = MainContent.FindControl("TextBox1") as TextBox;
        TB.ReadOnly = true;
    }
}

问题是...... 在使用 SiteLayout 的 MVC 应用程序中是否有等效的方法来执行此操作?

背景:我们购买了一个 MVC 应用程序并有权修改 源代码。我们需要自定义一些页面上的行为。它 只会被几十个人使用,所以性能影响不会很明显。如果这是一个 Web 表单 应用程序我们将使用上述方法。 然而这个应用程序 是用 MVC 编写的,它让我们的 web 表单程序员(我)对如何最好地进行感到困惑。自定义大量页面将是一个令人头疼的问题 我们必须修补软件。将所有更改集中在一个中心位置 以后会更容易管理。如何在 MVC 中拥有一个可以通过编程方式自定义其他页面的地方?

【问题讨论】:

    标签: asp.net-mvc webforms


    【解决方案1】:

    FindControl 没有等效的 MVC,因为视图是在单个操作中构建的,其中 ASP.NET 控件是针对多个不同事件构建和修改的。您无需查找控件,只需在构建时指定其所有属性。

    大致相当于 ASP.NET 控件(至少在此上下文中)是 HTML helper。 HTML 助手被实现为静态扩展方法,允许它们在视图之间共享,并在视图加载时执行一些操作。

    using System.Web.Mvc;
    using System.Web.Mvc.Html;
    
    public static class MyExtensions
    {
        public static MvcHtmlString TextBox1(this HtmlHelper helper, string name)
        {
            if (helper.ViewContext.HttpContext.Request.Path.ToUpper().Contains("/SAMPLE"))
            {
                return InputExtensions.TextBox(helper, name, null, new { @readonly = "readonly" });
            }
    
            return InputExtensions.TextBox(helper, name);
        }
    }
    

    用法

    ~/Views/Shared/_Layout.cshtml

    <!DOCTYPE html>
    <html lang="en">
        <head>
            <meta charset="utf-8" />
            <title>@ViewBag.Title - My ASP.NET MVC Application</title>
            <link href="~/favicon.ico" rel="shortcut icon" type="image/x-icon" />
            <meta name="viewport" content="width=device-width" />
            @Styles.Render("~/Content/css")
            @Scripts.Render("~/bundles/modernizr")
        </head>
        <body>
            <header>
                <div class="content-wrapper">
                    <div class="float-left">
                        <p class="site-title">@Html.ActionLink("your logo here", "Index", "Home")</p>
                    </div>
                    <div class="float-right">
                        <section id="login">
                            @Html.Partial("_LoginPartial")
                        </section>
                        <nav>
                            <ul id="menu">
                                <li>@Html.ActionLink("Home", "Index", "Home")</li>
                                <li>@Html.ActionLink("About", "About", "Home")</li>
                                <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
                            </ul>
                        </nav>
                    </div>
                </div>
            </header>
            <div id="body">
                @RenderSection("featured", required: false)
                <section class="content-wrapper main-content clear-fix">
    
                    @* Render custom HTML Helper *@
                    @Html.TextBox1("test")
    
                    @RenderBody()
                </section>
            </div>
            <footer>
                <div class="content-wrapper">
                    <div class="float-left">
                        <p>&copy; @DateTime.Now.Year - My ASP.NET MVC Application</p>
                    </div>
                </div>
            </footer>
    
            @Scripts.Render("~/bundles/jquery")
            @RenderSection("scripts", required: false)
        </body>
    </html>
    

    请注意,也可以将逻辑直接放在视图中,但是您不能在其他视图中重用逻辑,这会使您的视图看起来很混乱。

    至于从文本框中读回数据,您需要将其放在&lt;form&gt; 标记中,以便将其发布到控制器操作方法,这大致相当于提交按钮单击事件。与 ASP.NET 不同,MVC 支持多个 &lt;form&gt; 标签,因此您不必为页面上的不同操作混合逻辑。

    【讨论】:

    • 有没有办法在渲染时添加一个函数说“如果 Page = X 然后将 Textbox1 设置为 ReadOnly”?
    • 您可以使用sections 来做到这一点。您只需要覆盖每个适用视图上的部分(当 page = X 时)。但是你给出的例子是当 URL 包含/sample 时禁用文本框,所以这就是我提供的答案。
    • 该评论是针对其他帖子的。我马上删了。你太好了,不应该注意到它!
    • 有没有办法扩展 HTMLExtenders?例如,在 TextBoxFor 方法中添加另一个步骤?
    • 没有办法扩展它们,但由于它们是扩展方法,您可以添加自己的重载,以便它们无缝工作并且看起来就像现有的一样。您可以使用自己的名称创建扩展方法来指示自定义逻辑。您甚至可以创建templated HTML helpers,允许您在视图模板中自定义 HTML,而不是为每个场景创建 HTML 帮助程序。您只需在 /Views/web.config 文件中导入自定义 HTML 帮助程序命名空间,以便它们在您的视图中可见。
    【解决方案2】:

    您的问题非常广泛。但一般来说,如果您想根据某些条件为您的剃刀视图中的控件提供只读渲染,您可以尝试以下方法。

    您应该将IsReadOnly 属性添加到您的视图模型并使用它以您想要的方式呈现控件。

    public class CreateCustomerVM
    {
        public bool IsReadOnly {set;get;} 
    
        //Other properties goes here
        public string Email { set; get; }
        public string Name { set; get; }
    
    }
    

    在您的 Action 方法中,根据您的情况设置 IsReadOnly 属性值。

    public ActionResult Index()
    {
      var vm=new CreateCustomerVM();
    
      //Set the value based on your condition
      vm.IsReadOnly=true;
    
      return View(vm);    
    }
    

    在您看来,您使用IsReadOnly 属性来确定是否要显示只读控件。

    @model YourNameSpaceGoesHere.CreateCustomerVM
    @using (Html.BeginForm())
    {
        @Html.TextBoxFor(m => m.Email)
    
        if(Model.IsReadOnly)
        {
            @Html.TextBoxFor(m => m.Name, new { @readonly = "readonly" })
        }
        else
        {
            @Html.TextBoxFor(m => m.Name)
        }
        <input type="submit"/>
    }
    

    【讨论】:

    • 是的,这并没有像我想要的那样回答问题。这可能是我解释得不够清楚的错。我想要一个可以覆盖 MVC 中的控制行为的中心位置。我知道 MVC 是不同的,“控件”的概念与 Web 表单更一致。但是,我需要一个可以覆盖文本框/复选框/按钮/等...属性的位置。我知道这可能是一个奇怪的请求,但请记住,当商业 MVC 应用程序升级/修补时,我们需要一种易于管理的方式来管理更改。
    猜你喜欢
    • 1970-01-01
    • 2012-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-17
    • 2014-05-08
    • 2014-06-12
    • 1970-01-01
    相关资源
    最近更新 更多