Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Thema wird gezeigt, wie Sie die Klassen im Open XML SDK für Office verwenden, um eine benutzerdefinierte Eigenschaft in einem Textverarbeitungsdokument programmgesteuert festzulegen. Sie enthält eine Beispielmethode SetCustomProperty
zur Veranschaulichung dieser Aufgabe.
Der Beispielcode enthält außerdem eine Aufzählung, die die möglichen Typen benutzerdefinierter Eigenschaften bestimmt. Die SetCustomProperty
-Methode erfordert, dass Sie einen dieser Werte angeben, wenn Sie die -Methode aufrufen.
enum PropertyTypes : int
{
YesNo,
Text,
DateTime,
NumberInteger,
NumberDouble
}
Wie werden benutzerdefinierte Eigenschaften gespeichert?
Sie sollten wissen, wie benutzerdefinierte Eigenschaften in einem Textverarbeitungsdokument gespeichert werden. Sie können das Produktivitätstool für Microsoft Office (abbildung 1) verwenden, um zu ermitteln, wie sie gespeichert werden. Mit diesem Tool können Sie ein Dokument öffnen und seine Teile sowie deren Hierarchie anzuzeigen. Abbildung 1 zeigt ein Testdokument nach Ausführung des Codes im Abschnitt Aufrufen der SetCustomProperty-Methode in diesem Artikel. Das Tool zeigt in den rechten Bereichen sowohl die XML für den Teil als auch den entsprechenden C#-Code, mit dem Sie den Inhalt des Teils generieren können.
Abbildung 1: Open XML SDK Productivity Tool für Microsoft Office
Der entsprechende XML-Code wurde ebenfalls extrahiert und wird hier zum Vereinfachen des Lesens gezeigt.
<op:Properties xmlns:vt="https://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes" xmlns:op="https://schemas.openxmlformats.org/officeDocument/2006/custom-properties">
<op:property fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}" pid="2" name="Manager">
<vt:lpwstr>Mary</vt:lpwstr>
</op:property>
<op:property fmtid="{D5CDD505-2E9C-101B-9397-08002B2CF9AE}" pid="3" name="ReviewDate">
<vt:filetime>2010-12-21T00:00:00Z</vt:filetime>
</op:property>
</op:Properties>
Beim Untersuchen des XML-Inhalts werden Sie Folgendes feststellen:
- Jede Eigenschaft im XML-Inhalt besteht aus einem XML-Element, das den Namen und den Wert der Eigenschaft enthält.
- Für jede Eigenschaft enthält der XML-Inhalt ein
fmtid
Attribut, das immer auf den gleichen Zeichenfolgenwert festgelegt ist:{D5CDD505-2E9C-101B-9397-08002B2CF9AE}
. - Jede Eigenschaft im XML-Inhalt enthält ein
pid
Attribut, das eine ganze Zahl enthalten muss, die bei 2 für die erste Eigenschaft beginnt und für jede nachfolgende Eigenschaft inkrementiert werden muss. - Jede Eigenschaft verfolgt ihren Typ nach (in der Abbildung definieren die
vt:lpwstr
Elementnamen undvt:filetime
die Typen für jede Eigenschaft).
Die hier bereitgestellte Beispielmethode enthält den Code, der zum Erstellen oder Ändern einer benutzerdefinierten Dokumenteigenschaft in einem Microsoft Word-Dokument erforderlich ist. Den gesamten Code für diese Methode finden Sie im Abschnitt Beispielcode.
SetCustomProperty-Methode
Verwenden Sie die SetCustomProperty
-Methode, um eine benutzerdefinierte Eigenschaft in einem Textverarbeitungsdokument festzulegen. Die SetCustomProperty
-Methode akzeptiert vier Parameter:
Den Namen des zu ändernden Dokuments (Zeichenfolge)
Den Namen der hinzuzufügenden oder zu ändernden Eigenschaft (Zeichenfolge)
Den Wert der Eigenschaft (Objekt)
Die Art der Eigenschaft (einer der Werte in der
PropertyTypes
-Enumeration).
static string SetCustomProperty(
string fileName,
string propertyName,
object propertyValue,
PropertyTypes propertyType)
Aufrufen der SetCustomProperty-Methode
Mit SetCustomProperty
der -Methode können Sie eine benutzerdefinierte Eigenschaft festlegen und den aktuellen Wert der Eigenschaft zurückgeben, sofern vorhanden. Übergeben Sie zum Aufrufen der Beispielmethode die Parameter Dateiname, Eigenschaftenname, Eigenschaftenwert und Eigenschaftentyp. Der folgende Code zeigt ein Beispiel.
string fileName = args[0];
Console.WriteLine(string.Join("Manager = ", SetCustomProperty(fileName, "Manager", "Pedro", PropertyTypes.Text)));
Console.WriteLine(string.Join("Manager = ", SetCustomProperty(fileName, "Manager", "Bonnie", PropertyTypes.Text)));
Console.WriteLine(string.Join("ReviewDate = ", SetCustomProperty(fileName, "ReviewDate", DateTime.Parse("01/26/2024"), PropertyTypes.DateTime)));
Zeigen Sie nach der Ausführung dieses Codes mithilfe der folgenden Prozedur die benutzerdefinierten Eigenschaften in Word an.
- Öffnen Sie die .docx-Datei in Word.
- Klicken Sie auf der Registerkarte Datei auf Info.
- Klicken Sie auf Eigenschaften.
- Klicken Sie auf Erweiterte Eigenschaften.
Die benutzerdefinierten Eigenschaften werden im eingeblendeten Dialogfeld angezeigt (siehe Abbildung 2).
Abbildung 2: Benutzerdefinierte Eigenschaften im Dialogfeld "Erweiterte Eigenschaften"
Funktionsweise des Codes
Die SetCustomProperty
-Methode beginnt mit der Einrichtung einiger interner Variablen. Als Nächstes werden die Informationen zur -Eigenschaft untersucht und basierend auf den von Ihnen angegebenen Parametern ein neues CustomDocumentProperty erstellt. Der Code verwaltet auch die Variable propSet
, um anzugeben, ob das neue Eigenschaftsobjekt erfolgreich erstellt wurde. Dieser Code überprüft den Typ des Eigenschaftswerts und konvertiert dann die Eingabe in den richtigen Typ, wobei die entsprechende Eigenschaft des CustomDocumentProperty Objekts festgelegt wird.
Hinweis
Der CustomDocumentProperty Typ funktioniert ähnlich wie ein VBA Variant-Typ. Es verwaltet separate Platzhalter als Eigenschaften für die verschiedenen Datentypen, die darin enthalten sein können.
string? returnValue = string.Empty;
var newProp = new CustomDocumentProperty();
bool propSet = false;
string? propertyValueString = propertyValue.ToString() ?? throw new System.ArgumentNullException("propertyValue can't be converted to a string.");
// Calculate the correct type.
switch (propertyType)
{
case PropertyTypes.DateTime:
// Be sure you were passed a real date,
// and if so, format in the correct way.
// The date/time value passed in should
// represent a UTC date/time.
if ((propertyValue) is DateTime)
{
newProp.VTFileTime =
new VTFileTime(string.Format("{0:s}Z",
Convert.ToDateTime(propertyValue)));
propSet = true;
}
break;
case PropertyTypes.NumberInteger:
if ((propertyValue) is int)
{
newProp.VTInt32 = new VTInt32(propertyValueString);
propSet = true;
}
break;
case PropertyTypes.NumberDouble:
if (propertyValue is double)
{
newProp.VTFloat = new VTFloat(propertyValueString);
propSet = true;
}
break;
case PropertyTypes.Text:
newProp.VTLPWSTR = new VTLPWSTR(propertyValueString);
propSet = true;
break;
case PropertyTypes.YesNo:
if (propertyValue is bool)
{
// Must be lowercase.
newProp.VTBool = new VTBool(
Convert.ToBoolean(propertyValue).ToString().ToLower());
propSet = true;
}
break;
}
if (!propSet)
{
// If the code was not able to convert the
// property to a valid value, throw an exception.
throw new InvalidDataException("propertyValue");
}
Wenn der Code an diesem Punkt keine Ausnahme ausgelöst hat, können Sie davon ausgehen, dass die Eigenschaft gültig ist, und der Code legt die FormatId Eigenschaften und Name der neuen benutzerdefinierten Eigenschaft fest.
// Now that you have handled the parameters, start
// working on the document.
newProp.FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}";
newProp.Name = propertyName;
Arbeiten mit dem Dokument
Angesichts des CustomDocumentProperty -Objekts interagiert der Code als Nächstes mit dem Dokument, das Sie in den Parametern für die SetCustomProperty
Prozedur angegeben haben. Der Code beginnt mit dem Öffnen des Dokuments im Lese-/Schreibmodus mithilfe der Open -Methode der WordprocessingDocument -Klasse. Der Code versucht, mithilfe der -Eigenschaft des Dokuments einen Verweis auf den CustomFilePropertiesPart benutzerdefinierten Dateieigenschaftenteil abzurufen.
using (var document = WordprocessingDocument.Open(fileName, true))
{
var customProps = document.CustomFilePropertiesPart;
Wenn der Code den Teil mit den benutzerdefinierten Eigenschaften nicht findet, wird ein neuer Teil erstellt, dem eine neue Gruppe mit Eigenschaften hinzugefügt wird.
if (customProps is null)
{
// No custom properties? Add the part, and the
// collection of properties now.
customProps = document.AddCustomFilePropertiesPart();
customProps.Properties = new Properties();
}
Als Nächstes ruft der Code einen Verweis auf die Properties -Eigenschaft des benutzerdefinierten Eigenschaftenteils ab (d. a. einen Verweis auf die Eigenschaften selbst). Wenn der Code einen neuen Teil mit benutzerdefinierten Eigenschaften erstellen muss, wissen Sie, dass dieser Verweis kein Null-Verweis ist. Bei vorhandenen benutzerdefinierten Eigenschaftenteilen ist es jedoch möglich, obwohl es sehr unwahrscheinlich ist, dass die Properties Eigenschaft NULL ist. Falls doch, kann der Code nicht fortgesetzt werden.
var props = customProps.Properties;
if (props is not null)
{
Wenn die Eigenschaft bereits vorhanden ist, ruft der Code ihren aktuellen Wert ab und löscht anschließend die Eigenschaft. Warum wird die Eigenschaft gelöscht? Wenn der neue Typ der Eigenschaft ihrem vorhandenen Typ entspricht, könnte der Code den Wert der Eigenschaft auf den neuen Wert festlegen. Wenn dagegen der neue Typ nicht übereinstimmt, muss der Code ein neues Element erstellen und das alte löschen (der Typ des Elements wird durch seinen Namen bestimmt. Weitere Informationen finden Sie in Abbildung 1.) Es ist stets einfacher, das Element zu löschen und anschließend neu zu erstellen. Der Code verwendet eine einfache LINQ-Abfrage, um die erste Übereinstimmung für den Eigenschaftennamen zu finden.
var prop = props.FirstOrDefault(p => ((CustomDocumentProperty)p).Name!.Value == propertyName);
// Does the property exist? If so, get the return value,
// and then delete the property.
if (prop is not null)
{
returnValue = prop.InnerText;
prop.Remove();
}
Nun wissen Sie mit Sicherheit, dass der Teil mit der benutzerdefinierten Eigenschaft vorhanden ist, dass keine Eigenschaft vorhanden ist, die denselben Namen wie die neue Eigenschaft hat, und dass es möglicherweise andere vorhandene benutzerdefinierte Eigenschaften gibt. Der Code führt die folgenden Schritte aus:
Fügt die neue Eigenschaft als untergeordnete Eigenschaft an die Eigenschaftenauflistung an.
Durchläuft alle vorhandenen Eigenschaften und legt das
pid
Attribut auf steigende Werte fest, beginnend bei 2.Speichert den Teil.
// Append the new property, and
// fix up all the property ID values.
// The PropertyId value must start at 2.
props.AppendChild(newProp);
int pid = 2;
foreach (CustomDocumentProperty item in props)
{
item.PropertyId = pid++;
}
Schließlich gibt der Code den gespeicherten Wert der ursprünglichen Eigenschaft zurück.
return returnValue;
Beispielcode
Im Folgenden finden Sie das vollständige SetCustomProperty
Codebeispiel in C# und Visual Basic.
static string SetCustomProperty(
string fileName,
string propertyName,
object propertyValue,
PropertyTypes propertyType)
{
// Given a document name, a property name/value, and the property type,
// add a custom property to a document. The method returns the original
// value, if it existed.
string? returnValue = string.Empty;
var newProp = new CustomDocumentProperty();
bool propSet = false;
string? propertyValueString = propertyValue.ToString() ?? throw new System.ArgumentNullException("propertyValue can't be converted to a string.");
// Calculate the correct type.
switch (propertyType)
{
case PropertyTypes.DateTime:
// Be sure you were passed a real date,
// and if so, format in the correct way.
// The date/time value passed in should
// represent a UTC date/time.
if ((propertyValue) is DateTime)
{
newProp.VTFileTime =
new VTFileTime(string.Format("{0:s}Z",
Convert.ToDateTime(propertyValue)));
propSet = true;
}
break;
case PropertyTypes.NumberInteger:
if ((propertyValue) is int)
{
newProp.VTInt32 = new VTInt32(propertyValueString);
propSet = true;
}
break;
case PropertyTypes.NumberDouble:
if (propertyValue is double)
{
newProp.VTFloat = new VTFloat(propertyValueString);
propSet = true;
}
break;
case PropertyTypes.Text:
newProp.VTLPWSTR = new VTLPWSTR(propertyValueString);
propSet = true;
break;
case PropertyTypes.YesNo:
if (propertyValue is bool)
{
// Must be lowercase.
newProp.VTBool = new VTBool(
Convert.ToBoolean(propertyValue).ToString().ToLower());
propSet = true;
}
break;
}
if (!propSet)
{
// If the code was not able to convert the
// property to a valid value, throw an exception.
throw new InvalidDataException("propertyValue");
}
// Now that you have handled the parameters, start
// working on the document.
newProp.FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}";
newProp.Name = propertyName;
using (var document = WordprocessingDocument.Open(fileName, true))
{
var customProps = document.CustomFilePropertiesPart;
if (customProps is null)
{
// No custom properties? Add the part, and the
// collection of properties now.
customProps = document.AddCustomFilePropertiesPart();
customProps.Properties = new Properties();
}
var props = customProps.Properties;
if (props is not null)
{
// This will trigger an exception if the property's Name
// property is null, but if that happens, the property is damaged,
// and probably should raise an exception.
var prop = props.FirstOrDefault(p => ((CustomDocumentProperty)p).Name!.Value == propertyName);
// Does the property exist? If so, get the return value,
// and then delete the property.
if (prop is not null)
{
returnValue = prop.InnerText;
prop.Remove();
}
// Append the new property, and
// fix up all the property ID values.
// The PropertyId value must start at 2.
props.AppendChild(newProp);
int pid = 2;
foreach (CustomDocumentProperty item in props)
{
item.PropertyId = pid++;
}
}
}
return returnValue;
}