2014-04-23 29 views
0

我的问题是:如何传递集合和引用对象类型而不写这么多HiddenFors?MVC将集合和引用对象从BeginForm发送到视图?

这是我的模型:

public partial class AddressObject 
{ 
    public int ID { get; set; } 
    public string KeyNumber { get; set; } 
    public int AddressID { get; set; } 
    public int ObjectTypeID { get; set; } 
    public double ResidentalArea { get; set; } 
    public short ResidentsNumber { get; set; } 
    public Nullable<short> TuristBedsNumber { get; set; } 

    public virtual Address Address { get; set; } 
    public virtual ObjectType ObjectType { get; set; } 
    public virtual ICollection<TrashCan> TrashCans { get; set; } 
    public virtual ICollection<ObjectOwner> ObjectOwners { get; set; } 
} 

这是我的看法:

@Html.HiddenFor(model => model.Address.CityID); 
@Html.HiddenFor(model => model.Address.Hood); 
@Html.HiddenFor(model => model.Address.ID); 
@Html.HiddenFor(model => model.Address.Number); 
@Html.HiddenFor(model => model.Address.Region); 
@Html.HiddenFor(model => model.Address.Street); 
@Html.HiddenFor(model => model.Address.City.Addresses); 
@Html.HiddenFor(model => model.Address.City.ID); 
@Html.HiddenFor(model => model.Address.City.Name); 
@Html.HiddenFor(model => model.Address.City.PostalCode); 
@Html.HiddenFor(model => model.AddressID); 
@Html.HiddenFor(model => model.ObjectOwners); 
@Html.HiddenFor(model => model.ObjectType.ID); 
@Html.HiddenFor(model => model.ObjectType.Type); 
@Html.HiddenFor(model => model.ObjectTypeID); 
@Html.HiddenFor(model => model.TrashCans); 
@Html.HiddenFor(model => model.TuristBedsNumber); 

我不想写家居地址。我只想通过地址。我的收藏是ObjectOwners。我想做同样的事情。解决方案存在

编辑:我有Controller和在它的方法ActionResult(AddressObject addressObject)。在该控制器内部,我使用存储库调用unitOfWork来保存该实体。我的 HiddenFors包装@HtmlBeginForm("Save", "AddressObject")。当我将模型传递给控制器​​时,我的地址对象AddressObject.Addressnull = Count 0。我希望能够通过引用的对象和集合传递整个对象,而无需为引用的对象或集合的所有属性编写hiddenfors。

EDIT2: 我已经掌握详细情况(这并不重要),文本框都绑定到AddressObject我查看模型。所以我有例如@ Html.TextBoxFor(m => m.AddressID)。问题是,当我改变例如AddressObject.TurisBedsNumber时,每个被引用的对象或集合都会变为null,并且因为我的AddressObject在从View传递到Controller时与我的更新属性不一致。我希望我的引用和其他属性像更新之前一样不变。我已经尝试过Mvc Futures和序列化整个对象,我的对象及其集合和引用对象都可以。问题是,当我反序列化我的对象时,该对象没有用新的TuristBedNumber属性更新;这是旧的价值。我想知道如何保存我的藏品和其他物品的状态。我可以使用HiddenFor帮助程序(太多属性写入)来保存状态,或者我可以从我的存储库获取AddressObject或Collection,并在控制器中更新它;再次,太多的属性。我希望能够说“嘿你收集和我参考的对象,你不会改变什么”。我想整个序列化它们,但只有它们。 有人问控制器,但它是常见的:

public ActionResult(AddressObject addressObject) { unitOfWork.Update(addressObject) } 

是的,我有ValidState等....

+0

可不可以给更多的环境?你想达到什么目的? –

+0

已编辑的问题。 – Flipper

+0

在您的控制器中传递模型之前,您应该通过Linq查询来正确请求它以检索“Adress”。如果您使用控制器更新您的问题,可能会更容易为您提供帮助 –

回答

1

下面是我用的属性创建隐藏输入的辅助类。如果该属性是一个复杂类型,则它会递归地为复杂类型的每个属性创建隐藏输入。在你的情况下,你会使用@ Html.HiddenInputFor(m => m.Address)来生成全部17个输入。一定要在web.config中添加命名空间。

using System; 
using System.Collections; 
using System.Linq.Expressions; 
using System.Text; 
using System.Web.Mvc; 
using Sandtrap.Web.Extensions; 

namespace Sandtrap.Web.Html 
{ 

/// <summary> 
/// 
/// </summary> 
public static class HiddenInputHelper 
{ 

    /// <summary> 
    /// Returns the html for a hidden input(s) of a property. 
    /// </summary> 
    /// <typeparam name="TModel"></typeparam> 
    /// <typeparam name="TValue"></typeparam> 
    /// <param name="helper"></param> 
    /// <param name="expression"></param> 
    /// <param name="includeID"> 
    /// A value indicating the the 'id' attribute should be rendered for the input. 
    /// </param> 
    /// <remarks> 
    /// If the property is a complex type, the methods is called recursively for each property 
    /// of the type. Collections and complex types with null value (except those with the 
    /// Required attribute) are ignored. 
    /// </remarks> 
    public static MvcHtmlString HiddenInputFor<TModel, TValue> 
     (this HtmlHelper<TModel> helper, Expression<Func<TModel, TValue>> expression, bool includeID = false) 
    { 
     string name = ExpressionHelper.GetExpressionText(expression); 
     ModelMetadata metaData = ModelMetadata.FromLambdaExpression(expression, helper.ViewData); 
     StringBuilder html = new StringBuilder(); 
     return MvcHtmlString.Create(HiddenInput(metaData, name, includeID)); 
    } 

    /// <summary> 
    /// Returns the html for a hidden input(s) of a property defined by its metadata. 
    /// The string is not html-encoded. 
    /// </summary> 
    /// <param name="metaData"> 
    /// The metadata of the property. 
    /// </param> 
    /// <param name="name"> 
    /// The name of the property (rendered as the 'name' attribute). 
    /// </param> 
    /// <param name="includeID"> 
    /// A value indicating the the 'id' attribute should be rendered for the input. 
    /// </param> 
    /// <remarks> 
    /// If the property is a complex type, the methods is called recursively for each property 
    /// of the type. Collections and complex types with null value (except those with the 
    /// Required attribute) are ignored. 
    /// </remarks> 
    public static string HiddenInputForMetadata(ModelMetadata metaData, string name, bool includeID = false) 
    { 
     return HiddenInput(metaData, name, includeID); 
    } 

    #region .Helper methods 

    /// <summary> 
    /// Returns the html for a hidden input(s) of a property. 
    /// </summary> 
    /// <param name="metaData"> 
    /// The property metadata. 
    /// </param> 
    /// <param name="name"> 
    /// The name of the property (rendered as the 'name' attribute). 
    /// </param> 
    /// <param name="includeID"> 
    /// A value indicating the the 'id' attribute should be rendered for the input. 
    /// </param> 
    private static string HiddenInput(ModelMetadata metaData, string name, bool includeID) 
    { 
     StringBuilder html = new StringBuilder(); 
     if (metaData.ModelType.IsArray && metaData.Model != null) 
     { 
      // Primarily for database time stamps, this need to called before checking IsComplexType 
      // otherwise an endless loop is created 
      html.Append(HiddenInput(name, Convert.ToBase64String(metaData.Model as byte[]), includeID)); 
     } 
     else if (metaData.IsComplexType) 
     { 
      foreach (ModelMetadata property in metaData.Properties) 
      { 
       if (property.IsCollection() && !property.ModelType.IsArray) 
       { 
        // This would just render the Count and Capacity property of List<T> 
        continue; 
       } 
       if (property.Model == null && property.ModelType != typeof(string) && !property.IsRequired) 
       { 
        // Ignore complex types that are null and do not have the RequiredAttribute 
        continue; 
       } 
       // Recursive call to render a hidden input for the property 
       string prefix = string.Format("{0}.{1}", name, property.PropertyName); 
       html.Append(HiddenInput(property, prefix, includeID)); 
      } 
     } 
     else 
     { 
      html.Append(HiddenInput(name, metaData.Model, includeID)); 
     } 
     return html.ToString(); 
    } 

    /// <summary> 
    /// Returns the html for a hidden input. 
    /// </summary> 
    /// <param name="name"> 
    /// The name of the property. 
    /// </param> 
    /// <param name="value"> 
    /// The value of the property. 
    /// </param> 
    /// <param name="includeID"> 
    /// A value indicating the the 'id' attribute should be rendered for the input. 
    /// </param> 
    /// <returns></returns> 
    private static string HiddenInput(string name, object value, bool includeID) 
    { 
     TagBuilder input = new TagBuilder("input"); 
     input.MergeAttribute("type", "hidden"); 
     if (includeID) 
     { 
      input.MergeAttribute("id", HtmlHelper.GenerateIdFromName(name)); 
     } 
     input.MergeAttribute("name", name); 
     input.MergeAttribute("value", string.Format("{0}", value)); 
     return input.ToString(); 
    } 

    #endregion 

} 

} 

下面的扩展方法还需要

public static bool IsCollection(this ModelMetadata metaData) 
    { 
     if (metaData.ModelType == typeof(string)) 
     { 
      return false; 
     } 
     return typeof(IEnumerable).IsAssignableFrom(metaData.ModelType); 
    } 
+0

谢谢你的工作:) – Flipper

相关问题