過去数か月にわたって 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」の場合、1つだけ選択できるラジオボタンのセットを1つ表示したい。タイプが「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 モデルを持つことができますが、名前を指定する場合、リストが必要です。
アップデート
OK、なんとかこれを機能させましたが、目立たないチェックボックスの検証に問題があります。修正は次のとおりです。
メタデータ エディター テンプレートは次のようになります。
@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; }
}
送信時にモデルが正しく入力されるようになりました。ただし、エディター テンプレートによってレンダリングされたすべてのチェックボックスで検証が行われますが (クライアント検証をまだ実装していないため、ポスト アクション メソッドで)、MetaDataOption クラスの「選択済み」メンバーにはデータ注釈がありません。
注意事項 - チェックボックスが選択されていない場合、MetaData クラスの「Options」メンバーは null です。
Selected プロパティを null 許容 bool (bool?) に設定しようとしましたが、MetaDataOption エディター テンプレートの CheckBoxFor() ヘルパーが null 許容 bool を受け入れないという問題に遭遇しました。
これは私を夢中にさせています...私は、ASP.Netでやり遂げたであろう何かを機能させるために2日間を費やしました!