C# 验证属性来自模型但从渲染创建的下拉列表

C# 验证属性来自模型但从渲染创建的下拉列表,c#,asp.net,asp.net-mvc,C#,Asp.net,Asp.net Mvc,我有以下地址视图模型: 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 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>

@LabelFor(m=>m.Country)
@{
var countryCtrlName=Html.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(“国家”);
RenderAction(“列表”、“国家”,新的{ControlName=countryCtrlName});
}
@Html.ValidationMessageFor(m=>m.Country)
RenderAction(“List”)调用一个控制器方法,该方法从数据库中获取所有国家/地区,并使用下拉列表呈现和呈现部分,以下是视图:

@model IEnumerable<SelectListItem>
@{var controlName = (string)ViewBag.ControlName;}
@Html.DropDownList(controlName, Model, new {@class = ViewBag.CssClass})
@model IEnumerable
@{var controlName=(字符串)ViewBag.controlName;}
@DropDownList(controlName,Model,new{@class=ViewBag.CssClass})
即使我的DropdownList控件使用正确的名称呈现,并因此在POST时映射到正确的ViewModel,输入控件也没有使用必要的data val属性进行修饰以启用客户端验证(我认为这是因为partial的模型是IEnumerable,而不是保存国家名称的string属性

地址视图模型在我的应用程序中被用作许多视图的嵌套属性。关于如何验证它,有什么想法吗

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

公共类AddressViewModel { [StringLength(20,MinimumLength=2,ErrorMessage=“国家名称太短”)] 公共字符串国家{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; }

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

//Constructor to pass the list of countries
public AddressViewModel(IEnumerable<CountryViewModel> countries)
{
    this.CountryList = countries;
}
公共字符串城市{get;set;}
公共字符串Street{get;set;}
公共字符串编号{get;set;}
公共字符串ApartmentBuilding{get;set;}
公共字符串扇区{get;set;}
公共IEnumerable CountryList{get;set;}
//建造商通过国家名单
公共地址视图模型(IEnumerable国家/地区)
{
this.CountryList=国家;
}

}

我认为您的问题是对的:您没有将带注释的模型传递给局部视图,而是传递一个
SelectListItem
IEnumerable
。框架不知道您显示的是什么:它只知道如何调用它

我可以看出这样做很方便,但有点违背了MVC的精神。在这种情况下,您的“模型”实际上不是一个模型,它只是传递标记项列表(列表项)的一种方式


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

您是否尝试制作CountryModel并使用单独的控制器处理您的下拉列表。让控制器返回部分视图可以放在任何页面上。CountryModel上有一个带有IEnumerable的属性吗

地址视图:

@model AddressModel

@Html.Partial("nameOfPartialView", CountryModel)
型号:

public class CountryModel
{
    public IEnumerable<Countries> Countries { get; set; }
}
国家/地区下拉列表的局部视图:

@model CountryModel
@{var controlName = (string)ViewBag.ControlName;}
@Html.DropDownListFor(Model => Model.Countries)
接受国家/地区的控制员:

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

我不熟悉
KDropDownList
。谷歌告诉我它是
Keyoti.Search
的一部分。对吗?KDropDownList是我做的一个扩展,它用一些额外的类装饰下拉列表。这与调用Html.DropDownListFor相同(为了可读性,我还是更新了代码)我不想在每次需要呈现另一个实体的下拉列表时都创建不同的局部视图(有时下拉列表会用ajax调用的数据填充或更新)。将可能的国家列表与我的整个模型一起包含是一个好主意吗?我不想在发布时将整个国家列表重新发送回我的服务器,如果它是绑定模型的一部分,它会重新发送,对吗?不必。唯一返回的是标签的值。因此DropDownList的值将被发回,但不是
SelectListItems
。我如何在address视图上声明country属性的绑定?Robert,我根据您的回答更新了我的ViewModel。我假设每次在任何ViewModel上声明地址时,我都会使用数据库中的数据对其进行初始化,并将其传递给将要呈现的视图。很抱歉延迟响应,是的,这是正确的。另外,如果您的国家/地区列表始终相同,那么您应该对其进行缓存,这样您就不会在每次需要填充国家/地区列表时调用数据库。在地址视图上,您将添加带有国家/地区的部分视图。部分视图有其自己的模型t您不需要添加任何内容。因此,您的局部视图实际上只包含国家列表,并且您只需要在addressViewModel中使用int CountryId。我将调整我的答案以向您展示我的意思是的,现在每次我有一个控制器时,都会返回一个视图,其中包含一个具有嵌套addressViewModel作为属性的实体我只通过了一次国家列表(就像我在每次渲染视图请求数据库列表2到6次之前所做的那样)。再次感谢您的帮助。我将不得不寻找一种缓存策略,但要走得更远。
public ActionResult GetCountry(int CountryId)
{
     //do something with the selected country
}