0

我在自定义 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 页面中,在PlaceHolderMaincontent 元素下,我使用如下控件:

<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;
    }
}
4

2 回答 2

0

最初,我放弃了使用 SharePoint:CompositeField 和类似控件的整个想法。我回去使用基本的 ASP.Net 控件。除了处理附件,这工作得很好。但我不知道如何处理附件,但在我对解决方案的研究中,我注意到我可能能够继续使用默认的 SharePoint 列表表单。这就是我尝试过的,但后来我遇到了查找字段的问题。我无法让他们使用声明性 XML,必须在功能激活期间创建这些字段。这反过来又导致了场序列的问题。查找字段都出现在表单的末尾,而不是它们在其他字段中的正确位置。我试图通过使用FieldLinksCollection.Reorder(string[])方法,但这未能使用新的字段序列更新列表。

最终,我使用了声明性 XML 的组合来定义我的网站栏、内容类型、列表定义和列表实例。然后我使用了默认的列表形式。尽管 XML 中存在查找字段,但它们没有正确绑定,但我发现一些代码建议了一种以编程方式修复损坏的绑定的方法:https ://stackoverflow.com/a/18192756/1075980 。这种组合的行动解决了我的问题。

于 2013-08-12T17:20:23.393 回答
0

我不确定这是否适用于您的情况,但它可能有助于其他谷歌用户解决此错误。我遇到了同样的错误,发现原因是我不小心将 a 偷偷<SharePoint:CompositeField runat="server" />带入了我的ListFieldIterator. 我相信复合字段要么属于字段控件,要么必须定义一个属性来告诉它要呈现哪个字段。

于 2014-11-21T20:49:33.227 回答