The following (see the full code below) successfully adds a page in a section in Onenote. What I don't seem to be able to do is to get the lastly created page on top of the section. Here's the code that is puzzling me.

 onenoteApp.GetHierarchy(sectionId, OneNote.HierarchyScope.hsPages, out string xmlPages);
 var docPages = XDocument.Parse(xmlPages);
 var lastNode = docPages.LastNode;
 lastNode.Remove();
 docPages.AddFirst(lastNode);

GetHIerachy() just loads xml into xmlPages.

The problem is stricly XML, I don't think OneNote is a problem (at this stage), as docPage.document (the xml string) is in the same state at the end as when docPages was Parsed.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
using OneNote = Microsoft.Office.Interop.OneNote;

namespace CreateOneNotePage
{
    class Program
    {
        static OneNote.Application onenoteApp = new OneNote.Application();
        static XNamespace ns = null;
        static void Main(string[] args)
        {
            onenoteApp.GetHierarchy(null, OneNote.HierarchyScope.hsNotebooks, out string xml);
            GetNamespace();
            string notebookId = GetObjectId(null, OneNote.HierarchyScope.hsNotebooks, "CreateOnenotePage");
            string sectionId = GetObjectId(notebookId, OneNote.HierarchyScope.hsSections, "Projects");
            string pageId = CreatePage(sectionId, "TEst" + DateTime.Now.ToString("hhmmss"));
            Console.WriteLine(pageId);
            Console.ReadKey();
        }

        private static void GetNamespace()
        {
            string xml;

            onenoteApp.GetHierarchy(null, OneNote.HierarchyScope.hsNotebooks, out xml);
            var doc = XDocument.Parse(xml);
            ns = doc.Root.Name.Namespace;
        }
        static string GetObjectId(string parentId, OneNote.HierarchyScope scope, string objectName)
        {
            string xml;
            onenoteApp.GetHierarchy(parentId, scope, out xml);

            var doc = XDocument.Parse(xml);
            var nodeName = "";

            switch (scope)
            {
                case (OneNote.HierarchyScope.hsNotebooks): nodeName = "Notebook"; break;
                case (OneNote.HierarchyScope.hsPages): nodeName = "Page"; break;
                case (OneNote.HierarchyScope.hsSections): nodeName = "Section"; break;
                default:
                    return null;
            }

            var node = doc.Descendants(ns + nodeName).Where(n => n.Attribute("name").Value == objectName).FirstOrDefault();

            return node.Attribute("ID").Value;
        }
        static string CreatePage(string sectionId,string pageName)
        {
            onenoteApp.CreateNewPage(sectionId, out string pageId);
            onenoteApp.GetPageContent(pageId, out string xml, OneNote.PageInfo.piAll);
            var doc = XDocument.Parse(xml);
            var title = doc.Descendants(ns + "T").First();
            title.Value = pageName;
            onenoteApp.UpdatePageContent(doc.ToString());
            onenoteApp.GetHierarchy(sectionId, OneNote.HierarchyScope.hsPages, out string xmlPages);
            var docPages = XDocument.Parse(xmlPages);
            var lastNode = docPages.LastNode;
            lastNode.Remove();
            docPages.AddFirst(lastNode);
            onenoteApp.UpdateHierarchy(docPages.ToString());
            return pageId;
        }
    }
}

Dani AI

Generated

Short answer: the LINQ-to-XML methods are the right tool — move the XElement itself (not XNode.LastNode) and avoid removing the moved node after you insert it. was correct to point toward the XNode/XElement methods; the problem you ran into was using a brittle last-node selection and then removing the node in the wrong place.

A simple, safe pattern that avoids iterator/collection mutation issues is:

// get a stable list of Page elements
var pages = xDoc.Root.Elements(ns + "Page").ToList();

// find the page to move
var toMove = pages.Single(p => (string)p.Attribute("ID") == pageId);

// detach and insert at top
toMove.Remove();         // detach from its current parent
xDoc.Root.AddFirst(toMove);

// then send the full document back to OneNote
onenoteApp.UpdateHierarchy(xDoc.ToString());

Removing before inserting is explicit and avoids the subtle bug of calling Remove after a move (calling Remove after AddBeforeSelf will delete the moved node). Using AddFirst keeps intent clear.

Troubleshooting notes:

  • Prefer Elements(...) or Descendants(...).ToList() rather than LastNode, because LastNode can be whitespace or comments.
  • Always materialize the enumerable (ToList) before mutating the tree. Modifying while enumerating causes confusing behavior.
  • Keep the original XML namespace and root structure intact; OneNote expects the hierarchy XML in a particular shape. Confirm the resulting XML by calling GetHierarchy immediately after UpdateHierarchy to verify the server saw your change.

If the OneNote UI still shows the old order, the client may be sorting or caching (for example by timestamps or client-side cache). Verify the hierarchy XML returned by GetHierarchy; if the XML shows the new order but the UI does not, try forcing a client refresh or checking whether OneNote uses an attribute for display ordering.

Recommended Answers

All 4 Replies

Thank you very much. My problem inow s that docPages is a XNode and not an XmlNode. Only the latter seems to have a InserBefore method.

Would you have an idea how I should change my code so that I get XmlNodes?

You were right. It works now. Well OneNote does not seem not very happy, but that's another problem.
Many thanks for your help.

       static string CreatePage(string sectionId,string pageName)
        {
            onenoteApp.CreateNewPage(sectionId, out string pageId);
            onenoteApp.GetPageContent(pageId, out string xml, OneNote.PageInfo.piAll);
            var doc = XDocument.Parse(xml);
            var title = doc.Descendants(ns + "T").First();
            title.Value = pageName;
            onenoteApp.UpdatePageContent(doc.ToString());
            onenoteApp.GetHierarchy(sectionId, hsScope: OneNote.HierarchyScope.hsPages, pbstrHierarchyXmlOut: out string xmlPages);
            var xDoc = XDocument.Parse(xmlPages);
            var xPages = xDoc.Descendants(ns + "Page");
            XElement xFirstPage = xPages.FirstOrDefault();
            XElement xLastPage = xPages.Where(x => x.Attribute("ID").Value == pageId).FirstOrDefault();
            xFirstPage.AddBeforeSelf(xLastPage);
            xLastPage.Remove();
            onenoteApp.UpdateHierarchy(xDoc.ToString());
            return pageId;
        }
    }
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.