Необходимо передать параметр нескольким частичным представлениям на странице одного представления. - PullRequest
0 голосов
/ 24 сентября 2018

Я очень стараюсь переписать этот вопрос лучше, чем мои предыдущие попытки, которые не получили ответов.Несмотря на то, что я почти закончил с этим приложением, я все еще относительный новичок в программировании, и кажется, что одна проблема просто ведет к другой.Я просмотрел много сообщений, связанных с проблемой передачи параметра в несколько частичных представлений на одной странице просмотра.Итак, давайте рассмотрим это по порядку со страницы AlertPick.cshtml, где пользователь выбирает один из трех Alert_Identifier/SelectedAlertIndex параметров из базы данных приложения.Я показываю только @model и Select Tag Form.

@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, таблицу из пяти строк, где первые четыре строки представляют собой категории данных приложения: оповещение, информация, область и ресурс, каждый из которых имеет * 1007.* повторяется как напоминание в текстовом поле, за которым следует собственная кнопка отправки с именем 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 для _DetailsInfo(int? id) действия контроллера дляКатегория информационных данных.Он практически идентичен для каждой категории данных, за исключением того, что строка ... .SingleOrDefaultAsync(m => m.InfoIndex == id); становится ....SingleOrDefaultAsync(m => m.AlertIndex == id); and the method itself becomes _DetailsAlert (int? Id).

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

Метод PickAlert из AlertsController следует:

public IActionResult PickAlert(Alert obj, int? SelectedAlertIndex)
    {
        if (SelectedAlertIndex.HasValue)
        {
            ViewBag.Message = "Alert loaded successfully";
        }
        return View(_context.Alert.Where(x => x.AlertIndex == SelectedAlertIndex));
    }

Ответы [ 3 ]

0 голосов
/ 30 сентября 2018

В ядре .net, когда мне нужно передать много данных через представления, я обычно нахожу наиболее чистым использование служб и DI.Во-первых, вы можете создать класс, который может хранить набор данных:

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

}

Теперь вам нужно добавить этот класс в качестве службы.Для этого перейдите к классу запуска и добавьте следующее в функцию services:

services.AddScoped<MyDataForViews>();

Scoped означает, что инфраструктура будет создавать новый объект MyDataForViews для каждого HTTP-запроса.Независимо от того, сколько мест вы «внедрите» объект MyDataForViews, он будет использовать один и тот же объект в текущем HTTP-запросе.Вы также можете заменить функцию на 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, и нет необходимости передавать модели в каждое частичное представление.

0 голосов
/ 30 октября 2018

Вот немного более подробный ответ, поскольку на сайте softwareengineering.stackexchange.com вы сказали, что вам по-прежнему нужна помощь в этом.
Давайте сначала убедимся, что вы правильно понимаете основы.

Когда дело доходит до передачи данных в представление, каждый контроллер в ASP.NET MVC имеет свойство с именем ViewData, которое по сути является словарем пар ключ-значение.Само ViewData имеет свойство под названием Model, и это то, к чему вы обращаетесь на странице, используя синтаксис Razor @Model.Это свойство можно использовать для передачи модели со строгой типизацией, чтобы избежать использования магических строк для ключей ViewData.

Примечание. ViewBag - это динамическая оболочка для ViewData, поэтому по сути это одно и то же (ViewBag.SomeProperty совпадает с ViewData['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 (включая ссылку на Model), поэтому выне нужно делать ничего особенного , чтобы передать эти данные частичному представлению (но вы можете передать данные по вашему выбору, если хотите).

Помощник выбора тега визуализирует (генерирует HTML) дляэлемент select с указанными параметрами.Это тогда отправлено как HTML клиенту.На стороне клиента, когда пользователь нажимает кнопку отправки, на сервер отправляется запрос POST, который в конечном итоге обрабатывается методом PickAlert метода AlertsController.Если все настроено правильно, вы должны получить SelectedAlertIndex в качестве параметра.Обратите внимание, что это происходит на стороне сервера, и теперь вам нужно снова возвращать страницу в качестве ответа.

Вы можете выбрать соответствующий объект Alert из вашего _context.Для этого используйте метод FirstOrDefault вместо Where, так как вам нужен только один элемент (если необходимо, преобразуйте типы для сравнения - например, если у вас есть строка, но вы сравниваете с int или чем-то в этом духе)).

var selectedAlert = _context.Alert.FirstOrDefault(x => x.AlertIndex == SelectedAlertIndex);

Теперь все, что вам нужно сделать, это установить selectedAlert и любые другие данные, которые вам нужны, в качестве свойства объекта модели (или какого-либо ключа в ViewData), и отобразитьправильный вид.

Обратите внимание, что если вы просто return View(model) не указали имя представления, система будет искать представление с тем же именем, что и у вашего метода действия (здесь, PickAlert.cshtml), поэтому используйтеreturn View("ViewName", model) чтобы изменить это при необходимости.

Например, основываясь на коде, который вы разместили в своем вопросе, вы можете сделать что-то вроде этого:

[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);
}

YourViewName должно быть родительским представлением, которое имеет частичноепредставления в нем (я полагаю, представление «Собранное сообщение EDXL-CAP»).

Кстати, я знаю, что то, как система передает параметры в методы действий в контроллере, может показаться немного магическим, но оно основано на соглашениях.В приведенном выше примере это работает, потому что параметр называется SelectedAlertIndex, а объект модели имеет свойство с тем же именем (а также потому, что вы указали это свойство в помощнике тега select с помощью asp-for="SelectedAlertIndex").Вы также можете изменить сигнатуру метода так, чтобы он получал весь объект модели (при условии, что класс модели не слишком сложен - вы можете узнать больше о том, как работает привязка параметров здесь ):

    [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)
        // ...
    }

Теперь для частичных просмотров.Предполагая, что вы полагаетесь на механизм по умолчанию, который передает родительские ViewData каждому частичному представлению, вам нужно изменить каждое частичное представление так, чтобы код был написан в предположении, что вы можете получить доступ к выбранному предупреждению, используя @Model.SelectedAlert (свойство, которое выустановлено в действии PickAlert).

Например, вот простое частичное представление:

<div style="border: solid 1px #000000; padding: 30px; margin: 2px 2px 10px 2px;">
    <p>The selected index is: @Model.SelectedAlert.AlertIndex</p>
</div>

Обратите внимание, что я просто использую ту же модель, что и в родительском представлении, для доступа к объекту SelectedAlert: @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.) Это влияет только на свойство ViewData.Model;пары ключ-значение, хранящиеся в ViewData, остаются такими же, как в родительском представлении.

0 голосов
/ 25 сентября 2018

Я не уверен, правильно ли я получил требование, но я думаю, что вам нужно создать другую модель для всех 4 частичных представлений, например, для оповещения, создать новую модель

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

И затем ваше представлениебудет выглядеть так:

<!-- DetailsAlert -->
<div class="content-wrapper">
    @Html.Partial("_DetailsAlert",new AlertModel { Alert = Model.Alert,
                                                   SelectedAlertIndex = <ID SOMEHOW>
                                                 });
</div>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...