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 ドキュメントと、Web サーフィンから見つけたドキュメントはかなりまばらです...

このコントロールはどのように使用すればよいですか? それとも、基本的な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 に答える