为了解决这个问题,我失去了更多的头发,所以我真的希望你能帮忙吗?
我有一个Telerik MVC网格:
我有一个自定义的EditorTemplate for Address(Address.ascx)
我的ImporterDetails模型:
public class ImporterViewModel : IEnumerableViewModel
{
public int ImporterId { get; set; }
[Required]
[DisplayName("Importer Name *")]
public string ImporterName { get; set; }
[Required]
[DisplayName("Importer Address *")]
public Address ImporterAddress { get; set; }
public static ImporterViewModel CreateImporter()
{
return new ImporterViewModel
{
ImporterName = Guid.NewGuid().ToString().Substring(0, 5),
ImporterAddress = Address.CreateDummyAddress(),
};
}
}
和AddressViewModel:
[Bind(Exclude = "State, Country")]
public class Address
{
public int AddressId { get; set; }
[DisplayName("Address Line 1")]
[Required]
public string Line1 { get; set; }
[DisplayName("Address Line 2")]
public string Line2 { get; set; }
[DisplayName("Postcode")]
[Required]
[RegularExpression(RegexConstants.AUSTRALIAN_POSTCODE_PATTERN, ErrorMessage = "Invalid post code")]
public string Postcode { get; set; }
[DisplayName("State")]
public State State { get; set; }
[DisplayName("Suburb")]
public string Suburb { get; set; }
[DisplayName("Country")]
public Country Country { get; set; }
[Required]
public int CountryId { get; set; }
[Required]
public int StateId { get; set; }
/// <summary>
/// Creates a new dummy instance of Address
/// </summary>
/// <returns></returns>
public static Address CreateDummyAddress()
{
return new Address
{
Country = ServiceLocatorFactory.GetCodeServiceLocator<Country>().Get(x => x.CodeValue.ToLower() == "canada"),
State = ServiceLocatorFactory.GetCodeServiceLocator<State>().Get(x => x.CodeValue.ToLower() == "nsw"),
Line1 = Guid.NewGuid().ToString().Substring(0, 15),
Line2 = Guid.NewGuid().ToString().Substring(0, 15),
Suburb = "Dandenong",
Postcode = "2606",
};
}
public string AddressStrings
{
get
{
return ToString();
}
}
public override string ToString()
{
// create a blank StringBuilder
var sb = new StringBuilder();
// add the first address line
sb.Append(string.Format("{0}, ", Line1));
// add the second address line
sb.Append(string.Format("{0}, ", Line2));
sb.Append(string.Format("{0}, ", Suburb));
sb.Append(string.Format("{0} {1}, ", State == null ? string.Empty : State.Description, Postcode));
sb.Append(string.Format("{0}", Country == null ? string.Empty : Country.Description));
// and then return it as a single (formatted) string
return sb.ToString();
}
}
你会注意到我已经排除了状态和国家,因为如果我不这样做,当我调用TryUpdateModel(导入程序)时 - 我得到了可怕的无参数构造函数异常。我的问题是:
如何通过这种方式获取州和国家(或一般情况下,任何下拉列表)的正确ID?
为了完整起见:
Address.ascx
<div class="formElementGroupVertical">
<%: Html.LabelFor(m => m.Line1) %>
<%: Html.EditorFor(m => m.Line1) %>
<%: Html.ValidationMessageFor(m => m.Line1) %>
</div>
<div class="formElementGroupVertical">
<%: Html.LabelFor(m => m.Line2) %>
<%: Html.EditorFor(m => m.Line2) %>
<%: Html.ValidationMessageFor(m => m.Line2) %>
</div>
<div class="formElementGroupVertical">
<%: Html.LabelFor(m => m.Suburb) %>
<%: Html.EditorFor(m => m.Suburb)%>
<%: Html.ValidationMessageFor(m => m.Suburb)%>
</div>
<div class="formElementGroupVertical">
<%: Html.LabelFor(m => m.State) %>
<%: Html.EditorFor(m => m.State) %>
</div>
<div class="formElementGroupVertical">
<%: Html.LabelFor(m => m.Postcode) %>
<%: Html.EditorFor(m => m.Postcode)%>
<%: Html.ValidationMessageFor(m => m.Postcode)%>
</div>
<div class="formElementGroupVertical">
<%: Html.LabelFor(m => m.Country) %>
<%: Html.EditorFor(m => m.Country) %>
</div>
国家:
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Web.Common.Models.Country>" %>
<%@ Import Namespace="Web.Common.Models" %>
<%@ Import Namespace="Web.Common.Service" %>
<%: Html.DropDownListFor(m => m.CodeId, new SelectList(ServiceLocatorFactory.GetCodeServiceLocator<Country>().GetAll(), "CodeId", "Description"), "Please Select")%>
状态与国家相同,除了显而易见的。
任何帮助?
答案 0 :(得分:2)
CountryId没有被填充,因为DropDownlistFor是&#39; For&#39; country => country.CodeId
。
要获得CountryId,您实际上需要将下拉列表指向它:
Html.DropDownListFor(m => m.CountryId, new SelectList(ServiceLocatorFactory.GetCodeServiceLocator<Country>().GetAll(), "CodeId", "Description"), "Please Select")%>
获取下拉列表值的最简单方法是将DropDownListFor绑定到存储id的viewmodel上的属性。然后在您的控制器中,您可以生成(例如,通过数据库)该ID中的对象,并根据您的业务需求将其附加到任何模型。
这很麻烦但很直接。目前还没有通过下拉菜单AFAIK模拟绑定完整对象的自动方式。
在您的情况下,您的viewmodel将具有:
public class AddressViewModel
{
public int SelectedCountryId { get; set; }
}
然后以这种方式使用DropDownFor()
:
<%: Html.DropDownListFor(m => m.SelectedCountryId, new SelectList(ServiceLocatorFactory.GetCodeServiceLocator<Country>().GetAll(), "CodeId", "Description"), "Please Select")%>
然后在你的Action(伪代码)中:
public ViewResult Save(AddressViewModel addressVM)
{
var address = new Address() { Country = countriesStore.ById(addressVM.SelectedCountryId) };
address.Save();
...
}
这种方式也意味着您需要为视图使用视图模型而不是域模型。您的示例似乎正在使用域模型,因此您可能希望了解更改此问题。开始使用视图模型后,您还需要Automapper之类的内容,以便将视图模型映射到域模型。
答案 1 :(得分:0)
好的伙计们,我似乎对我的问题有一个临时的解决方法,并且很想知道您的反馈,以及可能使这个解决方案更“强大”的任何其他替代方案。
在我的操作中,我检查Request.Form并查找由复杂类型的PropertyName指定的下拉列表。所以语法如下:
下拉列表返回的PropertyName.PropertyName.Value字段。使用它,我可以在需要时查找存储库以获取ComplexType的实例。
我的行动被粘贴在下面以供参考:
[AcceptVerbs(HttpVerbs.Post)]
[GridAction]
public ActionResult Update(int id)
{
// obtain the instance of the importer we wish to update
var importer = serviceLocator.Get(i => i.ImporterId == id);
// the address object doesn't bind the State and Country dropdowns so we must manually read these
var stateCodeId = Request.Form["ImporterAddress.State.CodeId"];
var countryCodeId = Request.Form["ImporterAddress.Country.CodeId"];
//Perform model binding (fill the properties and validate the model)
if (TryUpdateModel(importer))
{
// parse the Id fields of the selected values of the dropdowns that we've just read from the request objects
importer.ImporterAddress.StateId = int.Parse(stateCodeId);
importer.ImporterAddress.CountryId = int.Parse(countryCodeId);
// and convert them to their specific code objects
importer.ImporterAddress.State =
ServiceLocatorFactory.GetCodeServiceLocator<State>().Get(s => s.CodeId == int.Parse(stateCodeId));
importer.ImporterAddress.Country =
ServiceLocatorFactory.GetCodeServiceLocator<Country>().Get(s => s.CodeId == int.Parse(countryCodeId));
// now save the updated model
serviceLocator.Update(importer);
}
// rebind the grid
return PartialView(new GridModel(serviceLocator.GetAll().ToList()));
}