MVC Razor - 创建/编辑视图最佳实践

22

这是我第一次使用MVC 3/Razor,所有的示例和VS脚手架都将创建和编辑视图的HTML视图分别放置。

实际上,在许多创建/编辑表单之间并没有太大区别,因此我想知道为什么找不到人们使用单个更新表单的示例,该表单可以用于创建和编辑操作。

我已经得到了Update.cshtml视图的解决方法,但是想知道它如何与控制器上的Edit或Create动作方法通信。

我的问题是:

  1. 是否有关于如何与控制器通信的快速答案?
  2. 是否有教程展示这种工作方式的良好实践?
  3. 当HTML通常相同时,将创建/编辑视图分开存储是否有充分的理由?

谢谢 Dave


可能是重复的问题:ASP.NET MVC - 使用相同的表单进行创建和编辑 - Ryan Kohn
5个回答

10

这个问题(好问题!)之前已经被问过:ASP.NET MVC - 使用相同的表单进行创建和编辑

基本上,您可以创建一个局部视图并将其包含在创建和编辑视图中。

Scott Guthrie在此处有一篇关于“局部视图”的不错的文章。

(我在某个地方读到过这个问题,但找不到了,如果我找到了,我会更新此帖子)


Scott Guthrie的博客文章是关于布局而不是部分视图的。 - Jeff LaFay
1
我不认为这是重复的问题;TS正在处理MVC 3。 - kite

8
请注意,对于您的问题的答案也应该受到业务需求(和角色)的驱动。脚手架确实提供了单独的功能,在某些情况下这可能是首选的实现。
从技术(编程)角度来看,CREATE 和 EDIT 功能通常非常相似。这可能会导致技术人员认为应该将功能合并以实现更有效的技术解决方案。然而,任何技术实现必须响应业务需求,这可能需要分离(例如根据业务角色)这些问题。
例如,一个企业可能要求 CREATE 业务对象的角色不同于 EDIT 业务对象的角色。在这种情况下,实现的 web 页面可能根本不会被相同的角色(和人员)看到。
如果您使用通用功能实现 CREATE 和 EDIT,但业务需求需要角色分离,则必须在呈现所需的视图/局部视图等之前实现“角色检查”。在这种情况下,单独的视图可以是首选的实现方式。

3

我这样做。我不知道是否最佳实践,但它可能很好用。有些情况下,完全独立的添加/编辑视图可能会很有用。此外,如果您正在使用ViewModels,则据我所知,您将被迫为添加和编辑使用相同的ViewModel。理论上,它们应该都有自己的ViewModels。

以下是我的做法:

AddVideo.cshtml

@model Multimedia.MediaVideoViewModel

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

@section AdditionalHeadContent {

}

<div class="page-header">
    <h1>Add a new video</h1>
</div>

<div id="add-video" class="row-fluid">
    @Html.Partial("_VideoForm", Model, new ViewDataDictionary { { "ActionKeyword", "Add" } })
</div>

EditVideo.cshtml

@model Multimedia.MediaVideoViewModel

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

@section AdditionalHeadContent {

}

@if (ViewBag.Success)
{
    <div class="alert alert-success">
    <button class="close" data-dismiss="alert">×</button>
        <h3><strong>Video saved!</strong></h3><br/>
        <div class="btn-group">
          <a href="#" class="btn">Preview this video</a>
          @Html.ActionLink("Add Another Video", "AddVideo", "Multimedia", new { Model.Id }, new { @class = "btn" })
          @Html.ActionLink("View all media", "Index", "Multimedia", null, new { @class = "btn" })
        </div>
        <p>or continue editing below...</p>
    </div>
}

<div class="page-header">
    <h1>Edit video <small>@Model.Title</small></h1>
</div>

<div id="edit-video" class="row-fluid">
    @Html.Partial("_VideoForm", Model, new ViewDataDictionary { { "ActionKeyword", "Edit" } })
</div>

_VideoForm.cshtml (局部视图)

@model Multimedia.MediaVideoViewModel

@{
    string actionKeyword = ViewData["ActionKeyword"].ToString();
}

<div class="span6">

    @using (Html.BeginForm("editvideo", "multimedia"))
    {
        <label class="control-label" id="embed-url">Paste video URL here:</label>
        <div class="control-group">
            @Html.TextBoxFor(model => model.EmbedUrl, new { @class = "span12", id = "video-url", placeholder = "ex: http://www.youtube.com/watch?v=PoAGasPLh30" })
            <button class="btn disabled" id="get-video" title="Tooltip">Get Video</button>
        </div>

        <div class="video-meta">

            <h3>Video Information</h3>
            <label class="control-label">Title:</label>

            <div class="control-group">
                @Html.TextBoxFor(model => model.Title, new { @class = "span12", id = "video-title" })
                @Html.ValidationMessageFor(model => model.Title, "A title is required", new { @class = "label label-important" })
            </div>

            <label class="control-label">Description:</label>
            <div class="control-group">
                @Html.TextAreaFor(model => model.Description, new { @class = "span12", id = "video-description" })
            </div>

            <h3>Categories</h3>

            <div id="tag-search" class="well">
                    <label class="control-label">Search tags:</label>
                    <div class="controls"><input type="text" class="typeahead" /></div>
                    @if (Model != null)
                    {
                        foreach (var category in Model.Tags)
                        {
                            @Html.Partial("_TagFragment", category)
                        }
                    }
            </div>

            <hr />

            @Html.HiddenFor(model => model.Id)
            @Html.HiddenFor(model => model.ThumbnailUrl, new { id = "thumb-url" })
            <input type="submit" id="video-submit" name="video-submit" class="btn-large btn-primary" value="@actionKeyword video" />
        </div>
    }

</div>

我稍微编辑了一下,可能会有些内容丢失,但这应该能给你一个大致的想法。


不要在AddVideo和EditVideo视图中创建新的ViewDataDictionary对象 - 验证消息将无法工作。 - Krahu

0

这是我的做法,不一定是最佳实践(具体情况具体分析)

1/ 将创建和编辑的控制器动作合并

public PartialViewResult Creedit(string id = null)
{
    if (id == null)
    {
        // Create new record (this is the view in Create mode)
        return PartialView();
    }
    else
    {
        // Edit record (view in Edit mode)
        Client x = db.ClientSet.Find(id);
        if (x == null) { return PartialView("_error"); }
        // ...
        return PartialView(x);
    }
}

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Creedit(Client x)
{
    if (x.id == null)
    {
        // insert new record
    }
    else
    {
        // update record
    }
}

2/ 将编辑和创建视图合并为一个名为Creedit的视图

// if you need to display something unique to a create view
// just check if the Model is null
@if(Model==null){
}

所以我有1个视图和2个操作(1个post和1个get),而不是2个视图和4个操作。


-1

同时也可以查看Nuget中的MVC脚手架,当它生成视图文件时,会明确地创建一个creatandedit部分,并使创建页面和编辑页面使用该部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接