0

複数のオブジェクトタイプのリストを含むモデルをASP.NETMVC3のポストバックアクションにバインドする方法を見つけようとしています。車両タイプのリストを定義する次のクラスがあります。

public enum VehicleType
{
    Car,
    Plane.
    Boat
}

public class BaseVehicle
{
    public VehicleType VehicleType { get; set; }
    public string Name { get; set; }
    public int Passengers { get; set; }
}

public class Plane : BaseVehicle
{
    public int WingSpan { get; set; }
    // -- etc --
}

// Properties omitted
public class Car : BaseVehicle {}
public class Boat : BaseVehicle {}

public class VehiclesViewModel
{
    public string Notes { get; set; }
    public List<BaseVehicle> Vehicles { get; set; }
}

上記のクラスは、次のビューで表示されます。

<!-- VehiclesView.cshtml - loaded by the controller -->
@model Mvc3Test.Models.VehiclesViewModel
<h2>Vehicles</h2>
@Html.EditorFor(m => m.Notes)
<hr />
@Html.EditorFor(m => m.Vehicles)

<!-- BaseVehicle.cshtml -->
@model BaseVehicle
@using Mvc3Test.Data
@Html.HiddenFor(m => m.VehicleType)
@{
    if (Model.VehicleType == VehicleType.Car)
    {
        Html.RenderPartial("Car", (Car)Model);
    }
    else if (Model.VehicleType == VehicleType.Plane)
    {
        Html.RenderPartial("Plane", (Plane)Model);
    }
    // etc..
}

<-- Plane.cshtml -->
@model Mvc3Test.Data.Plane
<h2>Plane</h2>
<p>Name: @Html.EditorFor(m => m.Name)</p>
<p>Passengers: @Html.EditorFor(m => m.Passengers)</p>
<p>Wingspan: @Html.EditorFor(m => m.WingSpan) metres</p>

<!-- Car.cshtml omitted -->

上記が表示(特にビュー内のifステートメント)を処理するための最良の方法であるかどうかはわかりませんが、今のところは機能します。問題は、viewmodelクラスにバインドする方法です。Html.TextBorFor()をHtml.TextBox()に置き換えて、バインディングプレフィックス( "Vehicles.Car"など)を追加できるようにしましたが、デフォルトのモデルバインダーを取得して決定する方法がないようです。適切なタイプをインスタンス化できるように、HTMLでどのような種類のクラスが表現されているか。

私はそれを解決するためにカスタムモデルバインダーを書かなければならないと思います-これは使用する正しい方法ですか、それとも私が逃した別の方法がありますか?

助けてくれてありがとう

4

1 に答える 1

2

初めに

if(Model.VehicleType == VehicleType.Car)
    {{
        Html.RenderPartial( "Car"、(Car)Model);
    }
    else if(Model.VehicleType == VehicleType.Plane)
    {{
        Html.RenderPartial( "Plane"、(Plane)Model);
    }

EditorFor.Worksでは省略できます。

バインドバックに関して-IMOの最良の方法は、カスタムモデルバインダーを作成することです。

例:

パブリッククラスDerivedTypeModelBinder:DefaultModelBinder
    {{
        パブリックオーバーライドオブジェクトBindModel(ControllerContext controllerContext、ModelBindingContext bindingContext)
        {{
            var typeName = GetVehicleType(bindingContext);
            if(typeName!= null)
            {{
                var modelType = Type.GetType(typeName);
                var targetTypeInstance = Activator.CreateInstance(modelType);
                bindingContext = new ModelBindingContext
                                     {{
                                         ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(()=> targetTypeInstance、modelType)、
                                         ModelState = bindingContext.ModelState、
                                         FallbackToEmptyPrefix = bindingContext.FallbackToEmptyPrefix、
                                         ModelName = bindingContext.FallbackToEmptyPrefix?string.Empty:bindingContext.ModelName、
                                         ValueProvider = bindingContext.ValueProvider、
                                     };
            }
            base.BindModel(controllerContext、bindingContext);を返します。
        }
        プライベート文字列GetVehicleType(ModelBindingContext bindingContext)
        {{
            var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName+"。"+"VehicleType");
            if(valueResult == null && bindingContext.FallbackToEmptyPrefix)
            {{
                valueResult = bindingContext.ValueProvider.GetValue( "VehicleType");
            }
            戻り値Result==null?null:valueResult.AttemptedValue;
        }
    }
于 2012-04-29T21:21:04.293 に答える