【问题标题】:Validation of a Dropdown which property comes from model but created from a RenderAction验证下拉列表的哪个属性来自模型但从 RenderAction 创建
【发布时间】:2013-02-21 20:28:30
【问题描述】:

我有以下地址 ViewModel:

public class AddressViewModel
{
    [StringLength(20, MinimumLength = 2, ErrorMessage = "Country name is too short")]
    public String Country { get; set; }

    public String City { get; set; }
    public String Street { get; set; }
    public String Number { get; set; }
    public String ApartmentBuilding { get; set; }
    public String Sector { get; set; }
}

以及呈现它的视图:

<div class="control-group offset2 span6">
    @Html.LabelFor(m => m.Country)
    <div class="controls">
        @{
            var countryCtrlName = Html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName("Country");
            Html.RenderAction("List", "Country", new { ControlName = countryCtrlName });
        }
        @Html.ValidationMessageFor(m => m.Country)
    </div>
</div>

Html.RenderAction("List") 调用一个控制器方法,该方法从数据库中获取所有国家/地区并使用下拉菜单进行渲染和渲染,这是视图:

@model IEnumerable<SelectListItem>
@{var controlName = (string)ViewBag.ControlName;}
@Html.DropDownList(controlName, Model, new {@class = ViewBag.CssClass})

即使我的 DropdownList 控件使用正确的名称呈现并因此在 POST 时映射到正确的 ViewModel,但输入控件并未使用启用客户端验证所需的 data-val 属性进行修饰(我相信这是因为部分的模型是 IEnumerable 而不是保存国家名称的字符串属性。

地址视图模型在我的应用程序中用作许多视图的嵌套属性。有关如何使其验证的任何想法?

编辑:根据@Robert 的回答更新 ViewModel:

公共类 AddressViewModel { [StringLength(20, MinimumLength = 2, ErrorMessage = "国家名称太短")] 公共字符串国家{得到;放; }

public String City { get; set; }
public String Street { get; set; }
public String Number { get; set; }
public String ApartmentBuilding { get; set; }
public String Sector { get; set; }

public IEnumerable<CountryViewModel> CountryList {get; set;}

//Constructor to pass the list of countries
public AddressViewModel(IEnumerable<CountryViewModel> countries)
{
    this.CountryList = countries;
}

}

【问题讨论】:

  • 我不熟悉KDropDownList。谷歌告诉我它是Keyoti.Search 的一部分。对吗?
  • KDropDownList 是我做的一个扩展,它用一些额外的类装饰下拉列表。和调用 Html.DropDownListFor 一样(为了可读性我还是更新了代码)

标签: c# asp.net asp.net-mvc


【解决方案1】:

您是否尝试过制作 CountryModel 并拥有一个单独的控制器来处理您的下拉列表。让控制器返回一个局部视图,您可以将其放在您想要的任何页面上。在 CountryModel 上拥有一个带有 IEnumerable 的属性?

地址查看:

@model AddressModel

@Html.Partial("nameOfPartialView", CountryModel)

型号:

public class CountryModel
{
    public IEnumerable<Countries> Countries { get; set; }
}

控制器:

public ActionResult Countries()
{
    var countries = //get the list from the database
    return PartialView(countries);
}

国家 DropDownList 的部分视图:

@model CountryModel
@{var controlName = (string)ViewBag.ControlName;}
@Html.DropDownListFor(Model => Model.Countries)

接受国家的控制器:

public ActionResult GetCountry(int CountryId)
{
     //do something with the selected country
}

【讨论】:

  • 如何在地址视图中声明国家/地区属性的绑定?
  • 罗伯特,我根据你的回答更新了我的 ViewModel。我假设每次我在任何 ViewModel 上声明一个地址时,我都会使用数据库中的数据对其进行初始化,然后将其传递给将要呈现的视图。
  • 很抱歉回复晚了,是的,这是正确的。另外,如果您的国家/地区列表始终相同,您应该考虑缓存它,这样您就不会在每次需要填充国家/地区列表时都调用数据库
  • 在地址视图中,您可以添加国家/地区的部分视图。局部视图有自己的模型,您无需添加任何内容。因此,您的部分视图实际上只包含国家/地区列表,而您的 addressViewModel 中只需要一个 int CountryId。我会调整我的答案来告诉你我的意思
  • 是的,现在每次我有一个控制器而不是返回一个带有嵌套 AddressViewModel 作为属性的实体的视图时,我只传递一次国家列表(就像我之前做的那样每个渲染视图请求数据库列表 2 到 6 次)。再次感谢您的帮助。我将不得不寻找一种缓存策略,但要走得更远。
【解决方案2】:

我认为您对问题所在是正确的:您没有将带注释的模型传递给局部视图,而是将 IEnumerable 传递给 SelectListItem。框架不知道您显示的内容代表什么:它只知道如何称呼它。

我可以看到这样做很方便,但它有点违反 MVC 的精神。在这种情况下,您的“模型”并不是真正的模型,它只是传递标记项列表(列表项)的一种方式。

我会使用整个AddressViewModel 作为您的模型。这样,您将保留数据注释中的信息,这些信息告诉您该属性的要求是什么。

【讨论】:

  • 我不想在每次需要呈现另一个实体的下拉列表时制作不同的局部视图(有时下拉列表会填充或更新来自 ajax 调用的数据)。在我的整个模型中包含可能的国家/地区列表是否是个好主意?我不想在 POST 上将整个国家/地区列表重新发送回我的服务器,如果它是绑定模型的一部分,它会,对吗?
  • 不一定。唯一被回发的是标签的值。所以 DropDownList 的值会被回传,而不是SelectListItems。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-05
  • 1970-01-01
  • 1970-01-01
  • 2011-09-18
  • 1970-01-01
相关资源
最近更新 更多