我在自定义 SharePoint 列表表单上收到此错误:异常详细信息:System.NullReferenceException:对象引用未设置为对象的实例。
Stack Trace:
[NullReferenceException: Object reference not set to an instance of an object.]
Microsoft.SharePoint.WebControls.CompositeField.get_Visible() +41
System.Web.UI.Control.PreRenderRecursiveInternal() +22
System.Web.UI.Control.PreRenderRecursiveInternal() +223
System.Web.UI.Control.PreRenderRecursiveInternal() +223
System.Web.UI.Control.PreRenderRecursiveInternal() +223
System.Web.UI.Control.PreRenderRecursiveInternal() +223
System.Web.UI.Control.PreRenderRecursiveInternal() +223
System.Web.UI.Control.PreRenderRecursiveInternal() +223
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3393
<SharePoint:CompositeField>
在我开始在我的表单中使用后,错误开始发生。我可能错了,但我正在尝试使用此控件,因为我认为它会自动适应我的各个字段的不同字段类型以及调整页面模式(新建、编辑或显示)。我怀疑我使用不正确,但是 MSDN 文档和我可以从网上冲浪中找到的任何文档都相当稀少......
我应该如何使用这个控件?还是我应该分解并使用基本的 asp.net 控件手动处理每个单独的字段?有更好的选择吗?在几十个字段中,有一些需要自定义工作 - 如果不是他们,其余字段将使用 SharePoint 的默认列表项表单处理得很好。
在我的 *.aspx 页面中,在PlaceHolderMain
content 元素下,我使用如下控件:
<asp:Content ID="Main" ContentPlaceHolderID="PlaceHolderMain" runat="server">
<!-- more content -->
<div id="main-form">
<!-- more content -->
<div>
<asp:Label runat="server" ID="LTSAttachmentsLabel" AssociatedControlID="LTSAttachmentsCompositeField" Text="Attach File" CssClass="label"></asp:Label>
<SharePoint:CompositeField runat="server" ID="LTSAttachmentsCompositeField" FieldName="LTS Attach File" />
</div>
<!--
about two dozen <div> tags; much of it similar to the above
with Label and CompositeField controls
-->
</div>
<!-- more content -->
</asp:Content>
我从严格的声明性使用开始,但在出现一系列错误并尝试修复它们之后,我现在在我的页面 PreInit 和 Load 事件中执行以下操作:
protected override void OnPreInit(EventArgs e)
{
base.OnPreInit(e);
_currentWeb = SPContext.Current.Web; // page-scoped property
string listGuid = Request.QueryString["List"];
_formList = _currentWeb.Lists[new Guid(listGuid)]; // page-scoped property
string itemGuid = Request.QueryString["Item"];
if (!itemGuid.IsNullOrEmptyTrimmed())
{
_itemID = itemGuid.ToIntegerNullSafe(); // page-scoped property
_item = _formList.GetItemById(_itemID.Value); // page-scoped property
}
_pageMode = (SPControlMode)Enum.Parse(typeof(SPControlMode), Request.QueryString["ControlMode"]); // page-scoped property
if (SPContext.Current.FormContext.FormMode == SPControlMode.Invalid && _pageMode != SPControlMode.Invalid)
{
SPContext.Current.FormContext.FormMode = _pageMode;
}
if (Request.QueryString["IsDlg"] != null)
{
_formIsDialog = Request.QueryString["IsDlg"] == "1"; // page-scoped property
}
if (Request.QueryString["ID"] != null)
{
_itemID = int.Parse(Request.QueryString["ID"]); // page-scoped property, unnecessary redundancy?
}
}
protected void Page_Load(object sender, EventArgs e)
{
// unrelated code
var spControls = from c in this.GetChildControlsRecursive()
where c is CompositeField
select c;
foreach (CompositeField cf in spControls)
{
cf.ListId = _formList.ID;
cf.ItemId = _itemID ?? -1;
}
// unrelated code
}
出于好奇,GetChildControlsRecursive
将所有子控件作为平面可枚举集合而不是分层集合返回。
// extension class in separate file
public static class ControlExtensions
{
public static IEnumerable<Control> GetChildControlsRecursive(this Control parentControl)
{
Stack<Control> todo = new Stack<Control>();
HashSet<Control> results = new HashSet<Control>();
todo.Push(parentControl);
results.Add(parentControl);
while (todo.Count > 0)
{
Control parent = todo.Pop();
foreach (Control child in parent.Controls)
if (results.Add(child))
todo.Push(child);
}
return results;
}
}