我已经全身心投入,并且互联网正在寻找解决方案,虽然我发现了一些让我接近的帖子,但他们最终都失败了#34;对象参考未设置为对象的实例"错误。
我正在尝试在MVC中创建"嵌套集合模型的变体以添加多个电话号码"来自Itorian.com,但我的复杂程度更高。
基本上,我有一个MVC 5 EF 6应用程序,其设置允许无限数量的电话号码与任何给定的联系人相关联。我使用链接表将联系人ID与电话ID相关联。目的是允许多个联系人(即,家庭成员)共享单个电话号码,同时还允许一个联系人具有多个电话号码。从第三个表格设置Phonetype(家庭,工作,小区等),允许下拉选择。 phonelink表包含phonetype_id,phone_id和contact_id的列。
我还应该注意,客户扩展了我的基础联系人。电话号码与联系人相关联,但我实际上是在创建客户端以同时生成扩展字段。如果我不在电话中输入电话,这种方法非常有效。
我的问题有两个:
首先: 我需要找出导致DropDownListFor
上的Object Reference Not Set错误的原因第二 确定在单击“添加电话号码”链接时如何正确地将新字段添加到视图中。关于此的更多细节。
我的模型类,由EF生成的数据库:
public partial class phone
{
public phone()
{
this.phonelinks = new HashSet<phonelink>();
}
public int id { get; set; }
public string phone_number { get; set; }
public string phone_extension { get; set; }
public virtual ICollection<phonelink> phonelinks { get; set; }
}
public partial class phonetype
{
public phonetype()
{
this.phonelinks = new HashSet<phonelink>();
}
public int id { get; set; }
public string phone_type { get; set; }
public virtual ICollection<phonelink> phonelinks { get; set; }
}
public partial class phonelink
{
public int id { get; set; }
public int contact_id { get; set; }
public int phone_id { get; set; }
public int phonetype_id { get; set; }
public virtual contact contact { get; set; }
public virtual phone phone { get; set; }
public virtual phonetype phonetype { get; set; }
}
我还扩展了phonelink以包含一个Remove From View帮助器属性(通过HTML Helpers和JS按预期工作):
public partial class phonelink
{
public bool remove_from_view { get; set; }
}
我的控制器用于新的联系人(只是GET,因为我的错误发生在尝试POST之前)
// GET: Clients/Create
public ActionResult Create()
{
var viewModel = new ClientCreateViewModel();
ConfigureCreateViewModel(viewModel);
return View(viewModel);
}
private void ConfigureCreateViewModel(ClientCreateViewModel model)
{
model.AllEthnicities = new SelectList(db.ethnicities, "id", "ethnicity1");
model.AllGenders = new SelectList(db.genders, "id", "gender1");
model.AllPrefixes = new SelectList(db.prefixes, "id", "prefix1");
model.AllSuffixes = new SelectList(db.suffixes, "id", "suffix1");
model.PhoneLinkVM = new PhoneLinkViewModel()
{
AllPhoneTypes = new SelectList(db.phonetypes, "id", "phone_type")
};
}
我的ViewModel(简化)
public class ClientCreateViewModel
{
public client Clients { get; set; }
public PhoneLinkViewModel PhoneLinkVM { get; set; }
// There are other declarations here for Ethnicities, Gender, etc.
// They all work for displaying dropdowns, so have been removed for simplicity
}
public class PhoneLinkViewModel
{
public IEnumerable<phonelink> Phonelinks { get; set; }
public IEnumerable<SelectListItem> AllPhoneTypes { get; set; }
public int SelectedPhoneType { get; set; }
public phonelink phonelink { get; set; }
}
在下面的视图中,我从编辑器模板中调用了phonelink。
@* Div for Phone Numbers *@
<div id="phoneNumbers">
@Html.EditorFor(model => model.PhoneLinkVM.phonelink)
</div>
<div class="row top-space">
<div class="form-group col-md-4 col-xs-12">
@Html.AddLink("Add Phone Number", "#phoneNumbers", ".phoneNumber", "Phonelinks", typeof(CreateClientViewModel))
</div>
</div>
@model TheraLogic.Models.ClientCreateViewModel
@using TheraLogic.Models
<div class="phoneNumber">
<div class="row top-space">
@* Phone Number Inputs *@
<div class="form-group col-md-2">
<label class="control-label">Phone Number</label>
@Html.EditorFor(model => model.PhoneLinkVM.phonelink.phone.phone_number, new { htmlAttributes = new { @class = "form-control" } })
@Html.HiddenFor(model => model.PhoneLinkVM.phonelink.remove_from_view, new { @class = "mark-for-removal" })
@Html.RemoveLink("Remove", "div.phoneNumber", "input.mark-for-removal")
</div>
<div class="form-group col-md-1">
<label class="control-label">Extension</label>
@Html.EditorFor(model => model.PhoneLinkVM.phonelink.phone.phone_extension, new { htmlAttributes = new { @class = "form-control" } })
</div>
<div class="form-group col-md-1">
<label class="control-label">Type</label>
@Html.DropDownListFor(model => model.PhoneLinkVM.SelectedPhoneType, Model.PhoneLinkVM.AllPhoneTypes, htmlAttributes: new { @class = "form-control" })
</div>
</div>
</div>
如果我在编辑器模板的底部注释掉@ Html.DropDownListFor,我可以查看Create view而不会出错。但有了它,就会产生Object Reference Not Set错误。
我能够使其完全正常工作的唯一方法是添加:
ViewBag.ThesePhoneTypes = model.PhoneLinkVM.AllPhoneTypes;
到ConfigureCreateViewModel的底部,并使用
将其拉入编辑器模板中的视图@Html.DropDownList("ThesePhoneTypes")
这更像是一种解决方法而非真正的解决方案。
关于在点击链接时添加/删除电话号码,如果我在Create.cshtml的@ Html.AddLink助手中使用type(phonelink)
,则会收到错误消息:
传递到字典中的模型项是类型的 &#39; phonelink&#39;,但这个字典需要一个模型项 键入&#39; Models.ClientCreateViewModel&#39;
但是如果我使用type(ClientCreateViewModel
然后而不是在我的Phonelink.cshtml编辑器模板中获取内容,我只是获取一组输入,用于在ClientCreateViewModel中为SelectedGender,SelectedEthnicity等声明的整数。上面的ViewModel代码,因为它们工作)。我知道我需要深入研究绑定嵌套的PhoneLinkViewModel,但我不确定如何去做。
(几乎逐字逐句地从上面的Itorian.com链接中获取)
public static class HtmlHelpers
{
public static IHtmlString RemoveLink(this HtmlHelper htmlHelper, string linkText, string container, string deleteElement)
{
var js = string.Format("javascript:removeNestedForm(this,'{0}','{1}'); return false;", container, deleteElement);
TagBuilder tb = new TagBuilder("a");
tb.Attributes.Add("href", "#");
tb.Attributes.Add("onclick", js);
tb.InnerHtml = linkText;
var tag = tb.ToString(TagRenderMode.Normal);
return MvcHtmlString.Create(tag);
}
public static IHtmlString AddLink<TModel>(this HtmlHelper<TModel> htmlHelper, string linkText, string container, string counter, string collectionProperty, Type nestedType)
{
var ticks = DateTime.UtcNow.Ticks;
var nestedObject = Activator.CreateInstance(nestedType);
var partial = htmlHelper.EditorFor(x => nestedObject).ToHtmlString().JsEncode();
partial = partial.Replace("id=\\\"nestedObject", "id=\\\"" + collectionProperty + "_" + ticks + "_");
partial = partial.Replace("name=\\\"nestedObject", "name=\\\"" + collectionProperty + "[" + ticks + "]");
var js = string.Format("javascript:addNestedForm('{0}','{1}','{2}','{3}');return false;", container, counter, ticks, partial);
TagBuilder tb = new TagBuilder("a");
tb.Attributes.Add("href", "#");
tb.Attributes.Add("onclick", js);
tb.InnerHtml = linkText;
var tag = tb.ToString(TagRenderMode.Normal);
return MvcHtmlString.Create(tag);
}
private static string JsEncode(this string s)
{
if (string.IsNullOrEmpty(s)) return "";
int i;
int len = s.Length;
StringBuilder sb = new StringBuilder(len + 4);
string t;
for (i = 0; i < len; i += 1)
{
char c = s[i];
switch (c)
{
case '>':
case '"':
case '\\':
sb.Append('\\');
sb.Append(c);
break;
case '\b':
sb.Append("\\b");
break;
case '\t':
sb.Append("\\t");
break;
case '\n':
break;
case '\f':
sb.Append("\\f");
break;
case '\r':
break;
default:
if (c < ' ')
{
string tmp = new string(c, 1);
t = "000" + int.Parse(tmp, System.Globalization.NumberStyles.HexNumber);
sb.Append("\\u" + t.Substring(t.Length - 4));
}
else
{
sb.Append(c);
}
break;
}
}
return sb.ToString();
}
}
我也可以添加Javascript,如果需要,但我认为没关系,因为它确实为视图添加了带字段的DIV,而不是我需要它的类型(phonelink)。
答案 0 :(得分:0)
您需要初始化PhoneLinkVM
。这不会导致调用其他HtmlHelper时出现问题,因为实际上没有计算作为第一个参数传递的表达式。但是,传递给DropDownListFor
的选择列表参数是一个直接变量引用,默认情况下PhoneLinkVM
为空。
要修复它,您只需要在视图模型中添加如下构造函数:
public class ClientCreateViewModel
{
public ClientCreateViewModel()
{
PhoneLinkVM = new PhoneLinkViewModel();
}
...
}
答案 1 :(得分:0)
虽然它没有真正回答为什么dropdownlistfor在编辑器模板中失败的问题,但我已经为我的项目找到了解决方案。
我完全抛弃了编辑器模板,现在将PhoneLink div渲染为部分。我刚刚决定使用另一种方法来添加额外的手机链接,这样就无需在我的情况下使用语音链接编辑器模板。
当我将@Html.EditorFor(model => model.PhoneLinkVM.phonelink)
更改为@Html.Partial("_PhonelinkPartial", Model.PhoneLinkPartial)
时(以及移动/重命名一些相关文件),我的视图按预期呈现。
我将使用JQuery和模态弹出窗口处理“添加电话号码”功能。