将ViewModel属性从局部视图绑定到主视图

时间:2016-09-28 17:00:25

标签: c# asp.net-mvc entity-framework razor

我是ASP.NET MVC的新手,基本上与网络相关。对不起,如果这是nooby,但我正在尝试这样做:

我有一个具有复杂属性的ViewModel(此处导航):

public class Request
{
    public virtual BaseRequestData RequestData { get; set; }
}

BaseRequestData是抽象的,但有一些继承自它的类,它们有其他类似的属性:

public class AcceleratorRequestData : BaseRequestData
{
    [Display(Name="Downside amount")]
    [Range(-100,0,ErrorMessage = "Downside participation must be between 0 and -100")]
    [Required]
    public decimal PutNotional { get; set; }

    [Display(Name="Upside strike")]
    [Range(1, 2, ErrorMessage = "Upside strike must be between 100% and 200%")]
    public decimal CallPercentStrike { get; set; }

}

在我的主'创建'视图中,我绑定到我的Request模型,但是我希望通过用户从下拉列表中选择它来根据其类型(例如,AcceleratorRequestData)为我的BaseRequestData创建部分视图。 我尝试过的是使用一些jQuery调用控制器并根据下拉列表呈现局部视图。这是我的部分视图之一,它是一堆表单组:

 @model Synapse.Models.AcceleratorRequestData

@Html.ValidationSummary(true,"",new {@class = "text-danger"})
<div class="form-group">
    @Html.LabelFor(m => Model.PutNotional, new {@class = "control-label col-md-2"})
    <div class="col-md-10">
        @Html.EditorFor(model => model.PutNotional, new {htmlAttributes = new {@class = "form-control"}})
        @Html.ValidationMessageFor(model => model.PutNotional, "", new {@class = "text-danger"})
    </div>
</div>
<div class="form-group">
    @Html.LabelFor(m => Model.CallPercentStrike, new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.CallPercentStrike, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.CallPercentStrike, "", new { @class = "text-danger" })
    </div>
</div>

在我的主视图中替换了我的占位符<div>

@using (Html.BeginHorizontalForm())
{
    @Html.AntiForgeryToken()

    <hr/>
    @Html.ValidationSummary(true, "", new {@class = "text-danger"})
    <div id="accelRequestPh" style="display: none;"></div>

    <input type="submit" value="Create" class="btn btn-default" />

}

但是这里我的验证属性和绑定失败了(显然,因为我的BaseRequestData对象没有绑定到我的Request对象的实例)。我怎样才能做到这一点?我应该使用编辑器模板吗?如果我这样做,我的主视图模型将如何知道它们?

2 个答案:

答案 0 :(得分:0)

AcceleratorRequestData添加到Request班级:

    public class Request
{
    public virtual BaseRequestData RequestData { get; set; }
    public  AcceleratorRequestData acceleratorRequestData { get; set; }
}

然后更改部分视图的模型:

@model Synapse.Models.Request.AcceleratorRequestData

答案 1 :(得分:0)

所以我放弃了下拉列表渲染不同的html元素,而我只是将下拉列表移动到上一页,以便它将具体的子类传递给视图。像这样:

我的下拉列表调用此控制器:

    /// <summary>
    /// Get the correct view depending on the dropdown
    /// </summary>
    /// <param name="productType"></param>
    /// <returns></returns>
    [HttpGet]
    public ActionResult Create(string productType)
    {
        Request request = new Request();
        switch (productType)
        {
            case "Accelerator":
                request.RequestData = new AcceleratorRequestData();
                request.ColloquialType = ColloquialType.Accelerator;
                return View(request);
            case "BarrierAccelerator":
                request.RequestData = new BarrierAcceleratorRequestData();
                request.ColloquialType = ColloquialType.BarrierAccelerator;
                return View(request);
            default:
                return RedirectToAction("Index", "Requests");
        }
    }

返回父视图:

@using (Html.BeginHorizontalForm())
{
    @Html.AntiForgeryToken()

    <hr/>
    @Html.ValidationSummary(true, "", new {@class = "text-danger"})
    @Html.EditorFor(x => x.RequestData)

    <input type="submit" value="Create" class="btn btn-default"/>
}

我在这里为每个BaseRequestData的孩子使用编辑器模板。这是一个:

@model Synapse.Models.AcceleratorRequestData

@Html.Hidden("ModelType", Model.GetType())           
@Html.ValidationSummary(true,"",new {@class = "text-danger"})
<div class="form-group">
    @Html.LabelFor(m => Model.PutNotional, new {@class = "control-label col-md-2"})
    <div class="col-md-10">
        @Html.EditorFor(model => model.PutNotional, new {htmlAttributes = new {@class = "form-control"}})
        @Html.ValidationMessageFor(model => model.PutNotional, "", new {@class = "text-danger"})
    </div>
</div>
<div class="form-group">
    @Html.LabelFor(m => Model.CallPercentStrike, new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.CallPercentStrike, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.CallPercentStrike, "", new { @class = "text-danger" })
    </div>
</div>

隐藏的html助手来自此链接:ViewModel with List<BaseClass> and editor templates

我还必须编辑我的global.cs

 public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            log4net.Config.XmlConfigurator.Configure(new FileInfo(Server.MapPath("~/Web.config")));
            ModelBinders.Binders.Add(typeof(BaseRequestData), new BaseRequestDataModelBinder());
        }
    }

    public class BaseRequestDataModelBinder : DefaultModelBinder
    {
        protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
        {
            ValueProviderResult typeValue = bindingContext.ValueProvider.GetValue(bindingContext.ModelName + ".ModelType");
            Type type = Type.GetType(
                (string)typeValue.ConvertTo(typeof(string)),
                true
            );
            object model = Activator.CreateInstance(type);
            bindingContext.ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, type);
            return model;
        }
    }

希望这有助于某人!