需要将参数传递给单个视图页面上的多个局部视图

时间:2018-09-24 20:51:05

标签: c# asp.net-mvc

与以前没有收到任何答复的努力相比,我正在努力重写这一问题。即使我几乎已经完成了此应用程序,但我还是编程方面的新手,似乎一个挑战会导致另一个挑战。我看过许多与在单个视图页面中将参数传递给几个局部视图的问题有关的文章。因此,让我们从AlertPick.cshtml页开始按顺序进行操作,在该页上,用户从应用程序数据库中选择三个Alert_Identifier/SelectedAlertIndex参数之一。我只显示@model和“选择标记表单”。

@model edxl_cap_v1_2.Models.ContentViewModels.EdxlCapMessageViewModel
@{
    <h4>@Model.Alerts.Count Alerts</h4>

    <form asp-controller="Alerts" asp-action="PickAlert" method="post">
        <select class="cap_select" id="cap_select" style="width:100%;max-width:95%;"
        asp-for="SelectedAlertIndex" asp-items="Model.Alert_Identifiers">
            <option>Select one</option>
        </select>
        <br />
        <input type="submit" name="PickAlert" value="Pick Alert to Assemble EDXL-Cap Message" />
    </form>
}

这会将用户带到PickAlert.cshtml页,该表由五行组成,其中前四行是应用程序的数据类别:警报,信息,区域和资源,每一个都重复Alert_Identifier作为提醒,请分别在文本框后跟自己的名为Check Alert, Check Info, Check Area, and Check Resource的提交按钮。这些提交按钮会将用户带到_DetailsAlert.cshtml, _DetailsInfo.cshtml, _DetailsArea.cshtml, and _DetailsResource.cshtml页,并且它们正常工作,并且数据项名称和记录中与Alert_Identifier相匹配的值。第五行重复“标识符”,其按钮显示为Add All,将整个集合组装在一起以供查看,并将用户带到下面的_Assemble.cshtml页面,其中各个数据类别已与数据项正确组装在一起名称,但缺少与Alert_Identifier对应的记录相匹配的正确数据值。我认为我需要为每个SelectedAlertIndex视图的Alert_Identifier@Html.Partial(...)添加第三个参数,但是我没有找到正确的格式/语法,如果有人可以提供这个信息或为我提供一个与此相似的示例,我将深表感谢。

@model edxl_cap_v1_2.Models.ContentViewModels.EdxlCapMessageViewModel

<!DOCTYPE html>

<head>
    <meta name="viewport" content="width=device-width" />
    <link rel="stylesheet" href="~/css/capv1_2_refimp.css" />
    <title>Assembled EDXL-CAP Message</title>
</head>

<h4>Assemble EDXL-CAP Message</h4>

<!-- DetailsAlert -->
<div class="content-wrapper">
    @Html.Partial("_DetailsAlert", Model.Alert)
</div>
<!-- End of DetailsAlert -->

<!-- DetailsInfo -->
<div class="content-wrapper">
    @Html.Partial("_DetailsInfo", Model.Info)
</div>
<!-- End of DetailsInfo -->

<!-- DetailsArea -->
<div class="content-wrapper">
    @Html.Partial("_DetailsArea", Model.Area)
</div>
<!-- End of DetailsArea -->

<!-- DetailsResource -->
<div class="content-wrapper">
    @Html.Partial("_DetailsResource", Model.Resource)
</div>
<!-- End of DetailsResource -->

响应下面的第一条评论,我显示了InfosController.cs的{​​{1}}代码,用于“信息数据类别”的控制器操作。除了行_DetailsInfo(int? id)变成... .SingleOrDefaultAsync(m => m.InfoIndex == id); _ DetailsAlert(int?id)之外,每个数据类别实际上都相同。

....SingleOrDefaultAsync(m => m.AlertIndex == id); and the method itself becomes
来自AlertsController的

PickAlert方法如下:

// GET: Infos/Details/5
    public async Task<IActionResult> _DetailsInfo(int? id)
    {
        if (id == null)
        {
            return NotFound();
        }

        var info = await _context.Info
            //.Include(e => e.Elements)
            //    .ThenInclude(d => d.DataCategory)
            .AsNoTracking()
            .SingleOrDefaultAsync(m => m.InfoIndex == id);

        if (info == null)
        {
            return NotFound();
        }

        return View(info);
    }

3 个答案:

答案 0 :(得分:0)

我不确定我是否正确理解了需求,但是我认为您必须为所有4个局部视图创建另一个模型,例如为Alert创建一个新模型

class AlertModel:EdxlCapMessageViewModel
{
  int SelectedAlertIndex {get;set;}
}

然后您的视图将如下所示:

<!-- DetailsAlert -->
<div class="content-wrapper">
    @Html.Partial("_DetailsAlert",new AlertModel { Alert = Model.Alert,
                                                   SelectedAlertIndex = <ID SOMEHOW>
                                                 });
</div>

答案 1 :(得分:0)

在.net核心中,当我需要在视图之间传递大量数据时,我通常发现使用服务和DI最干净。首先,您可以创建一个可以存储一组数据的类:

class MyDataForViews {
    // the following is an example. You can have any properties
    public string Info { get; set; }

}

您现在必须将此类添加为服务。为此,请转到您的启动类,然后在services函数中添加以下内容:

services.AddScoped<MyDataForViews>();

作用域表示该框架将为每个HTTP请求创建一个MyDataForViews新对象。不管您将MyDataForViews对象“注入”到多少位置,它都会在当前HTTP请求中使用相同的对象。如果要在整个Web应用程序中使用相同的对象,也可以用AddSingleton替换该功能。以下是将对象注入控制器的方式:

public class MyController : Controller
{

    MyDataForViews myData;

    // in controllers injection is done using the constructor 
    public MyController(MyDataForViews MyData) => myData = MyData;

    public IActionResult Index()
    {
        myData = ....   // assign all required data here
        View();
    }

}

完成此操作后,您可以使用以下方法将数据注入视图中,而不是将模型传递给每个视图:

@inject MyDataForViews MyData;

一旦在任何视图的顶部使用此行,就可以使用MyData对象,并且无需将模型传递给每个局部视图。

答案 2 :(得分:0)

这里有一个更详细的答案,因为您在softwareengineering.stackexchange.com网站上说过,您仍然需要帮助。
首先确保您正确理解了基础知识。

在将数据传递到视图时,ASP.NET MVC中的每个控制器都有一个名为ViewData的属性,该属性实质上是键值对的字典。 ViewData本身具有一个名为Model的属性,这是您使用Razor语法@Model在页面中访问的属性。您可以使用此属性传递强类型模型,以避免将魔术字符串用作ViewData的键。

注意:ViewBag是围绕ViewData的动态包装,因此它本质上是同一件事(ViewBag.SomePropertyViewData['SomeProperty']相同);但是,不建议使用ViewBag。

在执行类似return View()之类的控制器操作中,ASP.NET使用cshtml页面作为模板来创建实际的HTML,并将其作为对客户端的响应返回(这是所有服务器端)

有几种方法可以将数据传递给视图,例如:

ViewData.Model = someObject;
return View();

与以下相同:

return View(someObject);   // the View method can accept a model object

默认情况下,涉及到局部视图时,它们会通过父页面ViewData副本(其中包括对{{ 1}}),因此您无需执行任何特殊操作即可将此数据传递到局部视图(但是您可以根据需要传递您选择的数据)。

带有指定选项的select标记帮助器为select元素呈现(生成HTML)。然后将其作为HTML发送到客户端。在客户端,当用户单击“提交”按钮时,POST请求将发送到服务器,该请求最终由Model上的方法PickAlert处理。如果一切设置正确,则应获取AlertsController作为参数。请注意,这是在服务器端发生的,现在您需要再次返回页面作为响应。

您可以从SelectedAlertIndex中选择相应的Alert对象。为此,请使用_context方法,而不要使用FirstOrDefault,因为您只需要一个项目(必要时转换类型以进行比较-例如,如果您有字符串,但是要与int进行比较,或者遵循这些原则。

Where

现在,您需要做的就是将此var selectedAlert = _context.Alert.FirstOrDefault(x => x.AlertIndex == SelectedAlertIndex); 以及所有其他需要的数据设置为模型对象上的属性(或在ViewData中的某个键下),然后呈现正确的视图。

请注意,如果您只是selectedAlert而未指定视图名称,则系统将查找与您的操作方法名称相同的视图(此处为PickAlert.cshtml),因此请使用{{1}如有必要,请进行更改。

例如,根据您在问题中发布的代码,您可以执行以下操作:

return View(model)

return View("ViewName", model)应该是其中具有部分视图的父视图(我认为是“ Assembled EDXL-CAP Message”视图)。

顺便说一句,我知道系统将参数传递给控制器​​中的动作方法的方式看起来有点像魔术,但这是基于约定的。在上面的示例中,该参数之所以有效,是因为参数名为[HttpPost] public IActionResult PickAlert(int? SelectedAlertIndex) { var model = new EdxlCapMessageViewModel(/* ... params, if any */); if (SelectedAlertIndex.HasValue) { ViewBag.Message = "Alert loaded successfully"; var selectedAlert = _context.Alert.FirstOrDefault(x => x.AlertIndex == SelectedAlertIndex); // I added a property to your model to store the alert; // if you already have one, just use that one instead. model.SelectedAlert = selectedAlert; } return View("YourViewName", model); } ,并且模型对象具有名称相同的属性 (并且因为您已在select标记帮助器中指定了该属性使用YourViewName)。您还可以修改方法签名,以使其接收整个模型对象(假设模型类不是太复杂-您可以详细了解参数绑定的工作原理here):

SelectedAlertIndex

现在查看部分视图。假设您依赖于将父ViewData传递到每个局部视图的默认机制,则需要修改每个局部视图,以便在假设您可以使用asp-for="SelectedAlertIndex"访问选定警报的情况下编写代码(您在PickAlert操作中设置的属性)。

例如,这是一个简单的局部视图:

    [HttpPost]
    public IActionResult PickAlert(EdxlCapMessageViewModel model)
    {
        // extract the index from model.SelectedAlertIndex
        // you can also pass this same model object to the view 
        // (set some properties first if necessary)
        // ...
    }

请注意,我只是使用与父视图中相同的模型来访问SelectedAlert对象:@Model.SelectedAlert

同样,在渲染局部视图时,如果不传递其他参数,它们将获得<div style="border: solid 1px #000000; padding: 30px; margin: 2px 2px 10px 2px;"> <p>The selected index is: @Model.SelectedAlert.AlertIndex</p> </div> 字典的副本以及相同的@Model.SelectedAlert.AlertIndex

ViewData

如果您传递其他内容作为模型,例如仅传递选定的警报,则需要相应地更改部分视图代码:

Model

@Html.Partial("_DetailsAlert");

请注意,现在在局部视图中,本地@Html.Partial("_DetailsAlert", Model.SelectedAlert); 指的是父视图中的<div style="border: solid 1px #000000; padding: 30px; margin: 2px 2px 10px 2px;"> <p>The selected index is: @Model.AlertIndex</p> </div> 。 (换句话说,这里@Model的类型为@Model.SelectedAlert。)这仅影响@Model属性; Alert中存储的键值对仍然与父视图中的键值对相同​​。