输入值无法绑定至ViewModel,仅duration有值其余为null求助
问题描述
尝试将页面输入值传递到ViewModel的数组中,遍历修改后保存,但每次提交时,ViewModel数组里除了duration外,其余字段值均为null。已尝试修改控件名称和ID,问题仍未解决。
View 代码
@{ var SMs = ((List<Stage_Media>)ViewBag.Stage_Media); } <div class="col-lg-12"> <div class="card card-alt3"> <div class="card-header"> <h3><strong>Show Order</strong></h3> </div> <div class="card-body"> <table class="dd table" id="show_list"> <thead> <tr> <th></th> <th>Order</th> <th>Name</th> <th>Path</th> <th>Upload Date</th> <th>Duration (Min:Sec)</th> <th></th> </tr> </thead> @if (SMs.Count() > 0) { <tbody class="dd-list"> @for (int i = 0; i < SMs.OrderBy(sm => sm.order).Count(); i++) { var sm = SMs.OrderBy(sm => sm.order).ToList()[i]; <tr class="dd-item dd3-item" data-id="@sm.media.id" data-duration="@sm.duration"> <td class="dd-handle dd3-handle"></td> <td class="dd3-content">@sm.order</td> <td class="dd3-content">@sm.media.name</td> <td class="dd3-content">@sm.media.ext</td> <td class="dd3-content">@sm.media.uploaded</td> <td class="dd3-content"> @* 隐藏域传递media id *@ <input type="hidden" name="ids[@i].id" value="@sm.media.id" /> @if (sm.media.ext == "jpg" || sm.media.ext == "png") { <input name="ids[@i].duration" placeholder = "mm:ss" value = @(sm.duration != null ? TimeSpan.FromTicks((long)@sm.duration).ToString(@"m\:ss", null) : "00:10") /> } <input name="ids[@i].start_date" type="date" value="@(sm.start_date?.ToString("yyyy-MM-dd"))" /> <input name="ids[@i].end_date" type="date" value="@(sm.end_date?.ToString("yyyy-MM-dd"))" /> <select name="ids[@i].occurrence"> <option value="Everyday" @(sm.occurrence == "Everyday" ? "selected" : "")>Every day</option> <option value="Bi-Weekly" @(sm.occurrence == "Bi-Weekly" ? "selected" : "")>Bi-Weekly</option> </select> </td> <td style="width: 15%"> <div class="row align-items-center align-middle" style="margin: 0; height: 6em; max-height: 6em"> @if (sm.media.ext == "mp4" || sm.media.ext == "mov" || sm.media.ext == "mkv") { <video id="video_@i" src="/api/media?media_id=@sm.media.id" style="object-fit: cover; width: 100%; max-width: 100%; max-height: 100%" autoplay muted playsinline loop></video> } else { <img id="image_@i" src="/api/media?media_id=@sm.media.id" style="width: 100%; height:100%; object-fit: contain"> } </div> </td> </tr> } </tbody> } else { <tbody class="dd-empty"> <tr class="dd-placeholder"> <td></td> <td></td> <td></td> <td></td> <td></td> </tr> </tbody> } </table> </div> </div> </div> <div class="form-group row"> <div class="col-3"> <button type="button" name="Save" onclick="return saveStage(@ViewBag.Branch_id, @ViewBag.Stage.id);" class="btn btn-alt1">Save Stage</button> <button type="button" name="Delete" onclick="return deleteStage(@ViewBag.Stage.id);" class="btn btn-alt1">Delete Stage</button> <a name="View" href="/home/view?stage_id=@ViewBag.Stage.id" class="btn btn-alt1">View</a> </div>
ViewModel 代码
public class SaveStage_ViewModel { public int stage_id { get; set; } public string name { get; set; } public File[] ids { get; set; } public class File { public int id { get; set; } [DataType(DataType.Time)] [DisplayFormat(DataFormatString = "{mm\\:ss}")] [Display(Name = "Duration")] public string duration { get; set; } [Display(Name = "Start Date")] public DateTime? start_date { get; set; } [Display(Name = "End Date")] public DateTime? end_date { get; set; } [Display(Name = "Occurrence")] public string occurrence { get; set; } } }
Model 代码
public class Stage_Media { [Key] public int id { get; set; } public int stage_id { get; set; } [ForeignKey("stage_id")] public Stage stage { get; set; } public int media_id { get; set; } public long? duration { get; set; } [ForeignKey("media_id")] public Media media { get; set; } public int order { get; set; } public DateTime? start_date { get; set; } public DateTime? end_date { get; set; } public string occurrence { get; set; } }
Controller 代码
[HttpPost] public string SaveStage(SaveStage_ViewModel model) { using (var c = new Context()) { var stage = c.Stage.Find(model.stage_id); stage.name = model.name; stage.modified = DateTime.Now; stage.modified_by = User.Identity.Name; var sml = new List<Stage_Media>(); for (var i = 0; i < model.ids.Length; i++) { var sm = new Stage_Media(); sm.stage_id = model.stage_id; sm.media_id = model.ids[i].id; sm.start_date = model.ids[i].start_date; sm.end_date = model.ids[i].end_date; sm.occurrence = model.ids[i].occurrence; sm.order = i + 1; sm.duration = !string.IsNullOrWhiteSpace(model.ids[i].duration) ? (long?)TimeSpan.ParseExact(model.ids[i].duration, @"m\:ss", null).Ticks : null; sml.Add(sm); } c.Stage.Update(stage); c.Stage_Media.RemoveRange(c.Stage_Media.Where(smr => smr.stage_id == model.stage_id)); c.Stage_Media.AddRange(sml); c.SaveChanges(); } return $"Stage Save Successful"; }
问题原因及解决方法
- 模型绑定命名规则错误:ASP.NET MVC的数组模型绑定需要使用
数组名[索引].属性名的格式,原代码中input的name是sm_start_date这类固定名称,无法被识别为数组元素的属性,导致除了碰巧名称可能匹配的duration外,其他字段无法绑定。 - 缺少media id的传递:原代码没有将
sm.media.id传递到ViewModel的File.id字段,需要添加隐藏域来传递该值。 - 循环方式问题:原代码使用
foreach循环,无法方便地生成索引,改为for循环来生成数组索引。 - Controller中的笔误:原代码里
sm.end_date = model.ids[i].start_date;是错误的,应该改为sm.end_date = model.ids[i].end_date;。
调整后的View代码中,将所有input的name改为ids[@i].属性名的格式,添加了传递media id的隐藏域,并且用for循环生成索引,确保每个数组元素的属性都能正确绑定到ViewModel的ids数组中。
内容的提问来源于stack exchange,提问作者JavaFox
相关产品推荐
相关产品推荐

