C# 当涉及不同的模型时,如何将主视图和局部视图值传递给控制器?
原始问题: 这可能是一件简单的事情,但我已经找了30多个小时了,找不到适合我的答案(也尝试了很多方法) 所以,我试图实现的是,我必须在一个视图上显示一些数据,并且在同一个视图中获取一些值。为此,我创建了一个主视图,它显示一些数据并接收一些值。也是主视图中的局部视图,它还显示一些数据并接受一些值 主视图和局部视图的模型不同,相关的数据库表也不同 主视图模型:C# 当涉及不同的模型时,如何将主视图和局部视图值传递给控制器?,c#,asp.net-mvc,asp.net-core,partial-views,pass-data,C#,Asp.net Mvc,Asp.net Core,Partial Views,Pass Data,原始问题: 这可能是一件简单的事情,但我已经找了30多个小时了,找不到适合我的答案(也尝试了很多方法) 所以,我试图实现的是,我必须在一个视图上显示一些数据,并且在同一个视图中获取一些值。为此,我创建了一个主视图,它显示一些数据并接收一些值。也是主视图中的局部视图,它还显示一些数据并接受一些值 主视图和局部视图的模型不同,相关的数据库表也不同 主视图模型: public class VMBooking : VMBase { public int BookingID { g
public class VMBooking : VMBase
{
public int BookingID { get; set; }
public Guid BookingGUID { get; set; }
public int NoOfChildrenArrived { get; set; }
...
public List<VMBookingGuest> VMBookingGuests { get; set; }
...
}
@using VMBooking
<form class="form-horizontal" id="validation-form" method="post" defaultbutton="btnSubmit">
@Html.HiddenFor(c => c.BookingID)
@Html.HiddenFor(c => c.BookingGUID)
@Html.Partial("_Arrival", Model.VMBookingGuests)
<div class="form-group">
<input asp-for="@Model.NoOfChildrenArrived" type="text" id="NoOfChildrenArrived" />
</div>
<button type="submit" id="btnSubmit">Submit</button>
</form>
@foreach (var item in Model)
{
<tr class="center">
<td>@item.GuestName</td>
<td>@item.GuestCNIC</td>
<td>
<div>
<input id="IsGuestArrived" name="IsGuestArrived" asp-for="@item.IsGuestArrived" type="checkbox"/>
</div>
</td>
</tr>
}
现在,我已经成功地在部分视图中传递了部分视图模型,并且我的数据也正在显示
我的主视图CSHTML:
public class VMBooking : VMBase
{
public int BookingID { get; set; }
public Guid BookingGUID { get; set; }
public int NoOfChildrenArrived { get; set; }
...
public List<VMBookingGuest> VMBookingGuests { get; set; }
...
}
@using VMBooking
<form class="form-horizontal" id="validation-form" method="post" defaultbutton="btnSubmit">
@Html.HiddenFor(c => c.BookingID)
@Html.HiddenFor(c => c.BookingGUID)
@Html.Partial("_Arrival", Model.VMBookingGuests)
<div class="form-group">
<input asp-for="@Model.NoOfChildrenArrived" type="text" id="NoOfChildrenArrived" />
</div>
<button type="submit" id="btnSubmit">Submit</button>
</form>
@foreach (var item in Model)
{
<tr class="center">
<td>@item.GuestName</td>
<td>@item.GuestCNIC</td>
<td>
<div>
<input id="IsGuestArrived" name="IsGuestArrived" asp-for="@item.IsGuestArrived" type="checkbox"/>
</div>
</td>
</tr>
}
一切正常,但问题出现了,我必须在主视图上的一个提交按钮上提交这个组合输入数据(从主视图和部分视图)当我按下提交按钮时,只有来自主视图的值传递给控制器,而不是部分视图的值。
请注意,我必须为每个来宾条目将复选框值列表(id=“IsGuestArrived”)传递给控制器
正如前面所说,我已经尝试了许多不同的方法,但没有一种对我有效。因此,我想问,实现这一目标的合适方式是什么
编辑:
我已经找到了我的问题的答案,现在我想显示我根据@KingKing的建议对代码所做的更改
我所做的是在主视图中插入了partial标记,而不是@html.partial,因此主视图的代码如下所示
@using VMBooking
<form class="form-horizontal" id="validation-form" method="post" defaultbutton="btnSubmit">
@Html.HiddenFor(c => c.BookingID)
@Html.HiddenFor(c => c.BookingGUID)
<partial name="_Arrival" for="VMBookingGuests" />
<div class="form-group">
<input asp-for="@Model.NoOfChildrenArrived" type="text" id="NoOfChildrenArrived" />
</div>
<button type="submit" id="btnSubmit">Submit</button>
</form>
我曾经
model.VMBookingGuests = vmBooking.VMBookingGuests;
因为如果没有隐藏的值,就无法识别来宾ID。我认为应该如下更改局部视图的定义
[HttpGet]
public IActionResult Arrival(int id)
{
VMBooking model = _BookingRepo.GetBookingByID(id);
model.VMBookingGuests = _BookingRepo.GetGuestinfo(id);
PopulateDropdowns(model);
return View(model);
}
[HttpPost]
public IActionResult Arrival(VMBooking vmBooking)
{
VMBooking model = _BookingRepo.GetBookingByID(vmBooking.BookingID);
model.VMBookingGuests = _BookingRepo.GetGuestinfo(vmBooking.BookingID);
if (model != null)
{
_BookingRepo.ArrivalUpdate(vmBooking);
foreach (var item in model.VMBookingGuests)
{
_BookingRepo.GuestArrivalUpdate(item);
}
return RedirectToAction("Index");
}
PopulateDropdowns(model);
return View();
}
@Html.Partial("_Arrival", Model)
然后设置部分视图代码,如下所示,以将数据正确发送到控制器
@using VMBooking
@foreach (var item in Model.VMBookingGuests)
{
<tr class="center">
<td>@item.GuestName</td>
<td>@item.GuestCNIC</td>
<td>
<div>
<input id="IsGuestArrived" name="IsGuestArrived" asp-for="@item.IsGuestArrived" type="checkbox"/>
</div>
</td>
</tr>
}
editorforhelper可能更适合您尝试做的事情,但我建议您先简化一些事情(然后您就可以这样做了) 因此,与此相反(顺便说一句,这会生成一些无效标记): 然后modelbinder停止从索引“断开”的点重建
VMBookingGuests
列表,在该示例中,索引从1跳到4。它还将仅从类似于VMBookingGuests[0]的内容构建列表。SomePropertyHere
-您不能只从每个Guests获得名为SomePropertyHere
的输入,也不能使用类似于SomePropertyHere[]
的内容
现在,您可以在POST操作中看到以下内容:
foreach(model.VMBookingGuests中的变量项)
{
_预订报告-客房预订更新(项目);
}
这似乎表明您正在使用“数据”模型作为“视图”模型,并依靠您的ORM来找出发生了什么变化。在这种情况下,需要为来宾模型的每个属性添加隐藏字段。如果可以选择编写“服务”样式的方法,那么实际上只需要ID属性(BookingGuestID
,在您的情况下)和isguestarive
属性(因为这是唯一应该更改的内容)。类似方法的一个示例可能是:
public bool updateguestarivals(int bookingID,params VMBookingGuest[]guests)
{
布尔成功=假;
如果(来宾?.Any()==true)
{
foreach(客人中的var客人)
{
var bookingGuest=name of yourdbContexthere.VMBookingGuests.SingleOrDefault(m=>m.BookingID==BookingID&&m.BookingGuestID==guest.BookingGuestID);
if(bookingGuest!=null)
{
bookingGuest.isguestarive=guest.isguestarive;
}
}
yourdbContexthere.SaveChanges()的名称;
成功=真实;
}
回归成功;
}
在这个例子中有很多假设,但我认为这个想法很清楚。您可能可以将其更改为使用repo类。在局部视图中呈现的元素应该能够以正确的路径作为名称前缀进行呈现。使用
Html有点棘手。Partial
(最后会有一个解决方案)。但是,如果使用标记帮助器
,则使用for
属性(注意它不同于不会沿当前名称路径传递的model
属性)会更容易,如下所示:
@using VMBooking
<form class="form-horizontal" id="validation-form" method="post" defaultbutton="btnSubmit">
<input type="hidden" asp-for="BookingID" />
<input type="hidden" asp-for="BookingGUID" />
<table>
@for (int i = 0; i < Model.VMBookingGuests.Count; i++)
{
<tr class="center">
<td>@Model.VMBookingGuests[i].GuestName</td>
<td>@Model.VMBookingGuests[i].GuestCNIC</td>
<td>
<div>
<input type="checkbox" asp-for="VMBookingGuests[i].IsGuestArrived" />
<input type="hidden" asp-for="VMBookingGuests[i].BookingGuestID" />
</div>
</td>
</tr>
}
</table>
<div class="form-group">
<input asp-for="NoOfChildrenArrived" type="text" id="NoOfChildrenArrived" />
</div>
<button type="submit" id="btnSubmit">Submit</button>
</form>
<partial name="_Arrival" for="VMBookingGuests"/>
<!-- NOTE: this requires the view model of your partial view must support accessing item by index, like an IList -->
@for(var i = 0; i < Model.Count; i++) {
<tr class="center">
<td>@Model[i].GuestName</td>
<td>@Model[i].GuestCNIC</td>
<td>
<div>
<input id="IsGuestArrived-@i" asp-for="@Model[i].IsGuestArrived" type="checkbox"/>
</div>
</td>
</tr>
}
@{
var vd = new ViewDataDictionary(ViewData);
vd.TemplateInfo.Prefix = Html.NameFor(e => e.VMBookingGuests);
}
<!-- for Html.Partial -->
@Html.Partial("_Arrival", Model.VMBookingGuests, vd)
现在,随着前缀信息的传递,元素名称也会正确呈现,就像使用
时一样。当然,对于上面的部分视图,您仍然需要相同的更正代码。我相信有人会发布一个答案,允许您做您想做的事情。但我认为你应该为这些东西设置单独的控制器。MVC建议在函数集上分离控制器,而不是像旧的asp.net世界那样在页面上分离控制器,在旧的asp.net世界中,一个页面有一个pagebehind类。您的部分视图应该与另一个,bookingGuest
specific controller:)一起提供,因此,您的意思是,在点击单个提交按钮时,我需要调用两个不同的控制器操作?@ElsaK返回部分视图时,将附加到哪里?1.是否将其放置在表单标签中?2.如果是列表,则每个元素都需要一个name属性,该属性包含服务器端帖子上预期列表的索引。3.这些部分视图项是否包含在模型VMBooking
?,并且“否”您不需要调用两个控制器操作,也不需要使用新控制器来执行此操作。1。是的,我正在尝试将部分视图值放置在同一表单中。2.是的,这是一个列表,并且它也被编入了索引(或者至少我认为我正在创建一个VMBooking Guest列表,如上面的模型所示)3。不,部分vie
<partial name="_Arrival" for="VMBookingGuests"/>
<!-- NOTE: this requires the view model of your partial view must support accessing item by index, like an IList -->
@for(var i = 0; i < Model.Count; i++) {
<tr class="center">
<td>@Model[i].GuestName</td>
<td>@Model[i].GuestCNIC</td>
<td>
<div>
<input id="IsGuestArrived-@i" asp-for="@Model[i].IsGuestArrived" type="checkbox"/>
</div>
</td>
</tr>
}
@{
var vd = new ViewDataDictionary(ViewData);
vd.TemplateInfo.Prefix = Html.NameFor(e => e.VMBookingGuests);
}
<!-- for Html.Partial -->
@Html.Partial("_Arrival", Model.VMBookingGuests, vd)