Partager via


Ajouter un commentaire à une diapositive dans une présentation

Cette rubrique montre comment utiliser les classes du Kit de développement logiciel (SDK) Open XML pour Office pour ajouter un commentaire à la première diapositive d’une présentation par programme.

Remarque

Cet exemple concerne les commentaires modernes PowerPoint. Pour les commentaires classiques, consultez l’exemple archivé sur GitHub.

Structure de document de présentation de base

La structure de base d’un PresentationML document se compose d’un certain nombre de parties, parmi lesquelles la partie main qui contient la définition de présentation. Le texte suivant de la spécification ISO/IEC 29500 présente la forme globale d’un PresentationML package.

La partie main d’un PresentationML package commence par un élément racine de présentation. Cet élément contient une présentation qui, à son tour, fait référence à une liste de diapositives, à une liste de diapositives master, à une liste de notes master et à un document master liste. La liste des diapositives référence toutes les diapositives de la présentation ; la liste de masques de diapositive référence tous les masques de diapositive utilisés dans la présentation ; le masque de pages de note contient des informations sur la mise en forme des pages de notes et le masque de document décrit comment un document se présente.

Un document à distribuer est un ensemble imprimé de diapositives qui peut être distribué aux personnes de l’audience.

En plus de textes et de graphiques, chaque diapositive peut contenir des commentaires et des notes, peut avoir une disposition et peut faire partie d’une ou plusieurs présentations personnalisées. Un commentaire est une annotation destinée à la personne qui gère le jeu de diapositives de la présentation. Une note est un rappel ou un élément de texte destiné au présentateur ou à l’audience.

Les autres fonctionnalités qu’un PresentationML document peut inclure les suivantes : animation, audio, vidéo et transitions entre les diapositives.

Un PresentationML document n’est pas stocké sous la forme d’un corps volumineux dans une seule partie. Au lieu de cela, les éléments qui implémentent certains groupes de fonctionnalités sont stockés dans des composants distincts. Par exemple, tous les auteurs d’un document sont stockés dans une partie d’auteurs, tandis que chaque diapositive a sa propre partie.

ISO/IEC 29500 : 2016

L’exemple de code XML suivant représente une présentation qui contient deux diapositives ayant les numéros d’identification 267 et 256.

    <p:presentation xmlns:p="…" … > 
       <p:sldMasterIdLst>
          <p:sldMasterId
             xmlns:rel="https://…/relationships" rel:id="rId1"/>
       </p:sldMasterIdLst>
       <p:notesMasterIdLst>
          <p:notesMasterId
             xmlns:rel="https://…/relationships" rel:id="rId4"/>
       </p:notesMasterIdLst>
       <p:handoutMasterIdLst>
          <p:handoutMasterId
             xmlns:rel="https://…/relationships" rel:id="rId5"/>
       </p:handoutMasterIdLst>
       <p:sldIdLst>
          <p:sldId id="267"
             xmlns:rel="https://…/relationships" rel:id="rId2"/>
          <p:sldId id="256"
             xmlns:rel="https://…/relationships" rel:id="rId3"/>
       </p:sldIdLst>
           <p:sldSz cx="9144000" cy="6858000"/>
       <p:notesSz cx="6858000" cy="9144000"/>
    </p:presentation>

À l’aide du Kit de développement logiciel (SDK) Open XML, vous pouvez créer une structure de document et du contenu à l’aide de classes fortement typées qui correspondent aux éléments PresentationML. Vous trouverez ces classes dans l’espace de noms . Le tableau suivant répertorie les noms de classes des classes qui correspondent aux sldéléments , sldLayout, sldMasteret notesMaster .

Élément PresentationML Classe du Kit de développement logiciel (SDK) Open XML Description
<sld/> Slide Diapositive de présentation. Il s’agit de l’élément racine de SlidePart.
<sldLayout/> SlideLayout Mise en page des diapositives. Il s’agit de l’élément racine de SlideLayoutPart.
<sldMaster/> SlideMaster Masque des diapositives. Il s’agit de l’élément racine de SlideMasterPart.
<notesMaster/> NotesMaster Masque des pages de notes (ou handoutMaster). Il s’agit de l’élément racine de NotesMasterPart.

Structure de l’élément Modern Comment

L’élément XML suivant spécifie un seul commentaire. Il contient le texte du commentaire (t) et les attributs faisant référence à son auteur (authorId), à la date et à l’heure de création (created) et à l’ID de commentaire (id).

<p188:cm id="{62A8A96D-E5A8-4BFC-B993-A6EAE3907CAD}" authorId="{CD37207E-7903-4ED4-8AE8-017538D2DF7E}" created="2024-12-30T20:26:06.503">
  <p188:txBody>
      <a:bodyPr/>
      <a:lstStyle/>
      <a:p>
      <a:r>
          <a:t>Needs more cowbell</a:t>
      </a:r>
      </a:p>
  </p188:txBody>
</p188:cm>

Les tableaux suivants répertorient les définitions des attributs et éléments enfants possibles de l’élément cm (comment). Pour obtenir la définition complète , consultez MS-PPTX 2.16.3.3 CT_Comment

Attribut Définition
id Spécifie l’ID d’un commentaire ou d’une réponse de commentaire.
authorId Spécifie l’ID d’auteur d’un commentaire ou d’une réponse de commentaire.
status Spécifie le status d’un commentaire ou d’une réponse de commentaire.
créé Spécifie la date et heure de création de la réponse au commentaire ou au commentaire.
startDate Spécifie la date de début du commentaire.
dueDate Spécifie la date d’échéance du commentaire.
assignedTo Spécifie la liste des auteurs auxquels le commentaire est attribué.
Intégration Spécifie le pourcentage d’achèvement du commentaire.
title Spécifie le titre d’un commentaire.
Élément enfant Définition
pc :sldMkLst Spécifie un moniker de contenu qui identifie la diapositive à laquelle le commentaire est ancré.
ac :deMkLst Spécifie un moniker de contenu qui identifie l’élément de dessin auquel le commentaire est ancré.
ac :txMkLst Spécifie un moniker de contenu qui identifie la plage de caractères de texte à laquelle le commentaire est ancré.
unknownAnchor Spécifie une ancre inconnue à laquelle le commentaire est ancré.
Pos Spécifie la position du commentaire par rapport au coin supérieur gauche du premier objet auquel le commentaire est ancré.
replyLst Spécifie la liste des réponses au commentaire.
txBody Spécifie le texte d’un commentaire ou d’une réponse de commentaire.
extLst Spécifie une liste d’extensions pour un commentaire ou une réponse de commentaire.

L’exemple de schéma XML suivant définit les membres de l’élément cm en plus des attributs obligatoires et facultatifs.

 <xsd:complexType name="CT_Comment">
   <xsd:sequence>
     <xsd:group ref="EG_CommentAnchor" minOccurs="1" maxOccurs="1"/>
     <xsd:element name="pos" type="a:CT_Point2D" minOccurs="0" maxOccurs="1"/>
     <xsd:element name="replyLst" type="CT_CommentReplyList" minOccurs="0" maxOccurs="1"/>
     <xsd:group ref="EG_CommentProperties" minOccurs="1" maxOccurs="1"/>
   </xsd:sequence>
   <xsd:attributeGroup ref="AG_CommentProperties"/>
   <xsd:attribute name="startDate" type="xsd:dateTime" use="optional"/>
   <xsd:attribute name="dueDate" type="xsd:dateTime" use="optional"/>
   <xsd:attribute name="assignedTo" type="ST_AuthorIdList" use="optional" default=""/>
   <xsd:attribute name="complete" type="s:ST_PositiveFixedPercentage" default="0%" use="optional"/>
   <xsd:attribute name="title" type="xsd:string" use="optional" default=""/>
 </xsd:complexType>

Fonctionnement de l’exemple de code

L’exemple de code ouvre le document de présentation dans l’instruction using. Il instancie ensuite le composant CommentAuthorsPart et vérifie l’existence d’un composant auteurs de commentaires. Si ce n’est pas le cas, il en ajoute un.

// create missing PowerPointAuthorsPart if it is null
if (presentationDocument.PresentationPart.authorsPart is null)
{
    presentationDocument.PresentationPart.AddNewPart<PowerPointAuthorsPart>();
}

Le code détermine s’il existe un composant auteur PowerPoint existant dans le composant présentation . Si ce n’est pas le cas, il en ajoute une, puis vérifie s’il existe une liste d’auteurs et en ajoute une si elle est manquante. Il vérifie également que l’auteur qui est transmis figure sur la liste des auteurs existants ; Si c’est le cas, il attribue l’ID d’auteur existant. Si ce n’est pas le cas, il ajoute un nouvel auteur à la liste des auteurs et affecte un ID d’auteur et les valeurs de paramètre.

// Add missing AuthorList if it is null
if (presentationDocument.PresentationPart.authorsPart!.AuthorList is null)
{
    presentationDocument.PresentationPart.authorsPart.AuthorList = new AuthorList();
}

// Get the author or create a new one
Author? author = presentationDocument.PresentationPart.authorsPart.AuthorList
    .ChildElements.OfType<Author>().Where(a => a.Name?.Value == name).FirstOrDefault();

if (author is null)
{
    string authorId = string.Concat("{", Guid.NewGuid(), "}");
    string userId = string.Concat(name.Split(" ").FirstOrDefault() ?? "user", "@example.com::", Guid.NewGuid());
    author = new Author() { Id = authorId, Name = name, Initials = initials, UserId = userId, ProviderId = string.Empty };

    presentationDocument.PresentationPart.authorsPart.AuthorList.AppendChild(author);
}

Ensuite, le code détermine s’il existe un ID de diapositive et retourne s’il n’en existe pas.

// Get the Id of the slide to add the comment to
SlideId? slideId = presentationDocument.PresentationPart.Presentation.SlideIdList?.Elements<SlideId>()?.FirstOrDefault();

// If slideId is null, there are no slides, so return
if (slideId is null) return;

Dans le segment ci-dessous, le code obtient l’ID de relation. S’il existe, il est utilisé pour rechercher le composant diapositive, sinon la première diapositive des composants de diapositive énumérable est prise. Ensuite, il vérifie qu’il existe un composant de commentaires PowerPoint pour la diapositive et, si ce n’est pas le cas, il en ajoute un.

// Get the relationship id of the slide if it exists
string? relId = slideId.RelationshipId;

// Use the relId to get the slide if it exists, otherwise take the first slide in the sequence
SlidePart slidePart = relId is not null ? (SlidePart)presentationPart.GetPartById(relId) 
    : presentationDocument.PresentationPart.SlideParts.First();

// If the slide part has comments parts take the first PowerPointCommentsPart
// otherwise add a new one
PowerPointCommentPart powerPointCommentPart = slidePart.commentParts.FirstOrDefault() ?? slidePart.AddNewPart<PowerPointCommentPart>();

Sous le code crée un commentaire moderne, puis ajoute une liste de commentaires au composant de commentaire PowerPoint s’il n’en existe pas et ajoute le commentaire à cette liste de commentaires.

// Create the comment using the new modern comment class DocumentFormat.OpenXml.Office2021.PowerPoint.Comment.Comment
DocumentFormat.OpenXml.Office2021.PowerPoint.Comment.Comment comment = new DocumentFormat.OpenXml.Office2021.PowerPoint.Comment.Comment(
        new SlideMonikerList(
            new DocumentMoniker(),
            new SlideMoniker()
            {
                CId = cid,
                SldId = slideId.Id,
            }),
        new TextBodyType(
            new BodyProperties(),
            new ListStyle(),
            new Paragraph(new Run(new DocumentFormat.OpenXml.Drawing.Text(text)))))
{
    Id = string.Concat("{", Guid.NewGuid(), "}"),
    AuthorId = author.Id,
    Created = DateTime.Now,
};

// If the comment list does not exist, add one.
powerPointCommentPart.CommentList ??= new DocumentFormat.OpenXml.Office2021.PowerPoint.Comment.CommentList();
// Add the comment to the comment list
powerPointCommentPart.CommentList.AppendChild(comment);

Avec les commentaires modernes, la diapositive doit avoir la liste d’extensions et l’extension correctes. Le code suivant détermine si la diapositive possède déjà un SlideExtensionList et un SlideExtension et les ajoute à la diapositive s’ils ne sont pas présents.

// Get the presentation extension list if it exists
SlideExtensionList? presentationExtensionList = slidePart.Slide.ChildElements.OfType<SlideExtensionList>().FirstOrDefault();
// Create a boolean that determines if this is the slide's first comment
bool isFirstComment = false;

// If the presentation extension list is null, add one and set this as the first comment for the slide
if (presentationExtensionList is null)
{
    isFirstComment = true;
    slidePart.Slide.AppendChild(new SlideExtensionList());
    presentationExtensionList = slidePart.Slide.ChildElements.OfType<SlideExtensionList>().First();
}

// Get the slide extension if it exists
SlideExtension? presentationExtension = presentationExtensionList.ChildElements.OfType<SlideExtension>().FirstOrDefault();

// If the slide extension is null, add it and set this as a new comment
if (presentationExtension is null)
{
    isFirstComment = true;
    presentationExtensionList.AddChild(new SlideExtension() { Uri = "{6950BFC3-D8DA-4A85-94F7-54DA5524770B}" });
    presentationExtension = presentationExtensionList.ChildElements.OfType<SlideExtension>().First();
}

// If this is the first comment for the slide add the comment relationship
if (isFirstComment)
{
    presentationExtension.AddChild(new CommentRelationship()
    { Id = slidePart.GetIdOfPart(powerPointCommentPart) });
}

Exemple de code

Voici l’exemple de code complet montrant comment ajouter un nouveau commentaire avec un auteur nouveau ou existant à une diapositive avec ou sans commentaires existants.

Remarque

Pour obtenir le nom et les initiales de l’auteur, ouvrez le fichier de présentation et cliquez sur l’option de menu Fichier, puis cliquez sur Options. La fenêtre PowerPointOptions s’ouvre et le contenu de l’onglet Général s’affiche. Le nom et les initiales de l’auteur doivent correspondre au Nom d’utilisateur et aux Initiales affichés dans cet onglet.

static void AddCommentToPresentation(string file, string initials, string name, string text)
{
    using (PresentationDocument presentationDocument = PresentationDocument.Open(file, true))
    {
        PresentationPart presentationPart = presentationDocument?.PresentationPart ?? throw new MissingFieldException("PresentationPart");

        // create missing PowerPointAuthorsPart if it is null
        if (presentationDocument.PresentationPart.authorsPart is null)
        {
            presentationDocument.PresentationPart.AddNewPart<PowerPointAuthorsPart>();
        }

        // Add missing AuthorList if it is null
        if (presentationDocument.PresentationPart.authorsPart!.AuthorList is null)
        {
            presentationDocument.PresentationPart.authorsPart.AuthorList = new AuthorList();
        }

        // Get the author or create a new one
        Author? author = presentationDocument.PresentationPart.authorsPart.AuthorList
            .ChildElements.OfType<Author>().Where(a => a.Name?.Value == name).FirstOrDefault();

        if (author is null)
        {
            string authorId = string.Concat("{", Guid.NewGuid(), "}");
            string userId = string.Concat(name.Split(" ").FirstOrDefault() ?? "user", "@example.com::", Guid.NewGuid());
            author = new Author() { Id = authorId, Name = name, Initials = initials, UserId = userId, ProviderId = string.Empty };

            presentationDocument.PresentationPart.authorsPart.AuthorList.AppendChild(author);
        }

        // Get the Id of the slide to add the comment to
        SlideId? slideId = presentationDocument.PresentationPart.Presentation.SlideIdList?.Elements<SlideId>()?.FirstOrDefault();
        
        // If slideId is null, there are no slides, so return
        if (slideId is null) return;
        Random ran = new Random();
        UInt32Value cid = Convert.ToUInt32(ran.Next(100000000, 999999999));

        // Get the relationship id of the slide if it exists
        string? relId = slideId.RelationshipId;

        // Use the relId to get the slide if it exists, otherwise take the first slide in the sequence
        SlidePart slidePart = relId is not null ? (SlidePart)presentationPart.GetPartById(relId) 
            : presentationDocument.PresentationPart.SlideParts.First();

        // If the slide part has comments parts take the first PowerPointCommentsPart
        // otherwise add a new one
        PowerPointCommentPart powerPointCommentPart = slidePart.commentParts.FirstOrDefault() ?? slidePart.AddNewPart<PowerPointCommentPart>();

        // Create the comment using the new modern comment class DocumentFormat.OpenXml.Office2021.PowerPoint.Comment.Comment
        DocumentFormat.OpenXml.Office2021.PowerPoint.Comment.Comment comment = new DocumentFormat.OpenXml.Office2021.PowerPoint.Comment.Comment(
                new SlideMonikerList(
                    new DocumentMoniker(),
                    new SlideMoniker()
                    {
                        CId = cid,
                        SldId = slideId.Id,
                    }),
                new TextBodyType(
                    new BodyProperties(),
                    new ListStyle(),
                    new Paragraph(new Run(new DocumentFormat.OpenXml.Drawing.Text(text)))))
        {
            Id = string.Concat("{", Guid.NewGuid(), "}"),
            AuthorId = author.Id,
            Created = DateTime.Now,
        };

        // If the comment list does not exist, add one.
        powerPointCommentPart.CommentList ??= new DocumentFormat.OpenXml.Office2021.PowerPoint.Comment.CommentList();
        // Add the comment to the comment list
        powerPointCommentPart.CommentList.AppendChild(comment);
        
        // Get the presentation extension list if it exists
        SlideExtensionList? presentationExtensionList = slidePart.Slide.ChildElements.OfType<SlideExtensionList>().FirstOrDefault();
        // Create a boolean that determines if this is the slide's first comment
        bool isFirstComment = false;

        // If the presentation extension list is null, add one and set this as the first comment for the slide
        if (presentationExtensionList is null)
        {
            isFirstComment = true;
            slidePart.Slide.AppendChild(new SlideExtensionList());
            presentationExtensionList = slidePart.Slide.ChildElements.OfType<SlideExtensionList>().First();
        }

        // Get the slide extension if it exists
        SlideExtension? presentationExtension = presentationExtensionList.ChildElements.OfType<SlideExtension>().FirstOrDefault();

        // If the slide extension is null, add it and set this as a new comment
        if (presentationExtension is null)
        {
            isFirstComment = true;
            presentationExtensionList.AddChild(new SlideExtension() { Uri = "{6950BFC3-D8DA-4A85-94F7-54DA5524770B}" });
            presentationExtension = presentationExtensionList.ChildElements.OfType<SlideExtension>().First();
        }

        // If this is the first comment for the slide add the comment relationship
        if (isFirstComment)
        {
            presentationExtension.AddChild(new CommentRelationship()
            { Id = slidePart.GetIdOfPart(powerPointCommentPart) });
        }
    }
}

Voir aussi