1

我正在拔掉我遗漏的一点头发——在过去的几个月里一直在学习 MVC,所以我对它相对较新,尽管我已经涵盖了很多领域......

我在尝试使用相对复杂的视图模型输出复选框和单选按钮时遇到问题。

我有以下视图(删除了不相关的字段):

@model CreateMediumModel
@using(Html.BeginForm()) {
                <div class="formField">
                    <div class="label">
                        @Html.LabelFor(m => m.MetaData)
                    </div>
                    <div class="input">
                        @Html.EditorFor(m => m.MetaData)
                    </div>
                    @Html.ValidationMessageFor(m => m.MetaData)
                </div>

}

分层视图模型如下所示:

public class CreateMediumModel {
    public List<MetaData> MetaData { get; set; }
}

public class MetaData {
    /// <summary>
    /// The media type that this meta data belongs to.
    /// </summary>
    public int MediaTypeID { get; set; }

    /// <summary>
    /// The unique ID for the meta data.
    /// </summary>
    public int MetaDataID { get; set; }

    /// <summary>
    /// The unique text-based identifier for the meta data. Unique per MediaType.
    /// </summary>
    public string Key { get; set; }

    /// <summary>
    /// The UI description of the meta data.
    /// </summary>
    public string Description { get; set; }

    /// <summary>
    /// The max length of text based data.
    /// </summary>
    public int Length { get; set; }

    /// <summary>
    /// Provides a pre-defined list of values for the meta data.
    /// </summary>
    public List<MetaDataOption> Options { get; set; }

    /// <summary>
    /// Provides the text-based value for the meta data.
    /// </summary>
    public string Value { get; set; }

    /// <summary>
    /// Determines which value/s to use from the object graph
    /// </summary>
    public MetaDataDataType Type { get; set; }

    /// <summary>
    /// Defines the UI sort order of the meta data
    /// </summary>
    public int SortOrder { get; set; }
}

public class MetaDataDataType {
    public int MetaDataTypeID { get; set; }
    public MetaDataDataTypeEnum Type { get; set; }
    public bool TextBased { get; set; }
}

public class MetaDataOption {
    /// <summary>
    /// The unique ID for the option
    /// </summary>
    public int MetaDataOptionID { get; set; }

    /// <summary>
    /// The pre-defined option value to display.
    /// </summary>
    public string Value { get; set; }

    /// <summary>
    /// The sort order of the value in the list.
    /// </summary>
    public int SortOrder { get; set; }
}

public enum MetaDataEnum {
    Developer,
    PEGI,
    PEGIContent
}

public enum MetaDataDataTypeEnum {
    /// <summary>
    /// Simple text
    /// </summary>
    TEXT = 1,

    /// <summary>
    /// Multi-line text.
    /// </summary>
    MULTITEXT = 2,

    /// <summary>
    /// Simple number
    /// </summary>
    NUMBER = 3,

    /// <summary>
    /// Simple date
    /// </summary>
    DATE = 4,

    /// <summary>
    /// Simple time
    /// </summary>
    TIME = 5,

    /// <summary>
    /// Simple DateTime
    /// </summary>
    DATETIME = 6,

    /// <summary>
    /// Single option selection
    /// </summary>
    SELECTION = 7,

    /// <summary>
    /// Multi option selection
    /// </summary>
    MULTISELECTION = 8
}

每条元数据都有一个类型;类型定义了元数据的编辑方式和显示方式(以及数据在数据层中的存储位置)。事物的显示方面工作得非常好。

当类型为“SELECTION”时,我想显示一组单选按钮,其中只能选择一个。当类型为“MULTISELECTION”时,我想显示一组复选框,其中可以选择多个。我可以这样做,但我已经能够成功地将选定的值绑定到模型。

目前,我正在使用编辑器模板来显示列表,如下所示:

@model MetaData
@using Business.Enumerations

@if(Model != null) {
    @Html.HiddenFor(m => m.MetaDataID)
    <div class="metaData@(Model.MediaTypeID) checkbox">
        <div class="metaDescription">
            @Model.Description
        </div>
        <div class="metaValue">
            @switch(Model.Type.Type) {
                case MetaDataDataTypeEnum.NUMBER:
                case MetaDataDataTypeEnum.DATE:
                case MetaDataDataTypeEnum.TEXT:
                case MetaDataDataTypeEnum.TIME:
                case MetaDataDataTypeEnum.DATETIME:
                    @Html.TextBoxFor(m => m.Value)
                    break;
                case MetaDataDataTypeEnum.MULTITEXT:
                    @Html.TextAreaFor(m => m.Value)
                    break;
                case MetaDataDataTypeEnum.SELECTION:
                    foreach(var o in Model.Options) {
                        @Html.RadioButtonFor(m => m.Value, o.MetaDataOptionID) @o.Value
                    }
                    break;
                case MetaDataDataTypeEnum.MULTISELECTION:
                    foreach(var o in Model.Options) {
                        @Html.CheckBoxFor(m => m.Options.FirstOrDefault(opt => opt.Selected).Selected) @o.Value
                    }
                    break;
   }
        </div>
    </div>
}

当我解决这个问题时,这将被扩展,但现在,它会按预期输出所有内容 - 我看到 SELECTION 类型的单选按钮列表和 MULTISELECTION 类型的复选框列表,但是当我调用时它没有正确绑定到模型提交动作。

我有点疯了。谁能看到我做错了什么明显的事情?

作为旁白:

我也尝试为 MetaDataOption 类创建一个编辑器模板,但是当指定模板名称(Html.EditorFor(m => m.Options , "MetaDataOptionsSingle") 和 Html.EditorFor(m => m.Options, "MetaDataOptionsMulti")) - 如果我没有为编辑器模板指定名称,则模板可以具有 MetaDataOption 模型,但如果指定名称,它需要一个列表。


更新

好的,我已经设法让它工作了,但是我现在遇到了不显眼的复选框验证问题。修复如下:

MetaData 编辑器模板现在看起来像这样:

@model MetaData
@using Business.Enumerations

@if(Model != null) {
    @Html.HiddenFor(m => m.Description)
    @Html.HiddenFor(m => m.Type)
    <div class="metaData@(Model.MediaTypeID) checkbox">
        <div class="metaDescription">
            @Model.Description
        </div>
        <div class="metaValue">
            @switch (Model.Type) {
                case MetaDataDataTypeEnum.NUMBER:
                case MetaDataDataTypeEnum.DATE:
                case MetaDataDataTypeEnum.TEXT:
                case MetaDataDataTypeEnum.TIME:
                case MetaDataDataTypeEnum.DATETIME:
                    @Html.TextBoxFor(m => m.Value)
                    break;
                case MetaDataDataTypeEnum.MULTITEXT:
                    @Html.TextAreaFor(m => m.Value)
                    break;
                case MetaDataDataTypeEnum.SELECTION:
                    if(Model.Options != null) {
                        foreach (var o in Model.Options) {
                            @Html.RadioButtonFor(m => Model.SelectedMetaDataOptionID, o.MetaDataOptionID)
                            @o.Value
                        }
                    }
                    break;
                case MetaDataDataTypeEnum.MULTISELECTION:
                    @Html.EditorFor(m => m.Options)
                    break;
            }
        </div>
    </div>
}

我为 MULTISELECTION EditorFor 添加了另一个 EditorTemplate:

@model MetaDataOption

@if(Model != null) {
    @Html.HiddenFor(m => m.MetaDataOptionID)
    @Html.CheckBoxFor(m => m.Selected)
    @Model.Value
}

而MetaDataOption类如下:

public class MetaDataOption {
    /// <summary>
    /// The unique ID for the option
    /// </summary>
    public int MetaDataOptionID { get; set; }

    /// <summary>
    /// The pre-defined option value to display.
    /// </summary>
    public string Value { get; set; }

    /// <summary>
    /// The sort order of the value in the list.
    /// </summary>
    public int SortOrder { get; set; }
}

现在,模型在提交时可以正确填充。但是,验证发生在编辑器模板呈现的所有复选框上(在 post 操作方法中,因为我还没有实现客户端验证),但 MetaDataOption 类的“Selected”成员上没有数据注释。

需要注意的是 - 如果未选中任何复选框,则 MetaData 类的“选项”成员为空。

我尝试将 Selected 属性设置为可为空的布尔值(布尔值?),但遇到了 MetaDataOption 编辑器模板中的 CheckBoxFor() 帮助器不接受可为空的布尔值的问题。

这让我发疯了......我花了两天时间试图让我用 ASP.Net 快速完成的工作!

4

0 回答 0