You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

输入值无法绑定至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";
}
问题原因及解决方法
  1. 模型绑定命名规则错误:ASP.NET MVC的数组模型绑定需要使用数组名[索引].属性名的格式,原代码中input的name是sm_start_date这类固定名称,无法被识别为数组元素的属性,导致除了碰巧名称可能匹配的duration外,其他字段无法绑定。
  2. 缺少media id的传递:原代码没有将sm.media.id传递到ViewModel的File.id字段,需要添加隐藏域来传递该值。
  3. 循环方式问题:原代码使用foreach循环,无法方便地生成索引,改为for循环来生成数组索引。
  4. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 18:26:58