有没有人想过如何使用Open XML SDK 2.0向Excel添加评论?我无法找到有关此问题开始的文档。如何使用Open XML SDK 2.0将评论添加到Excel 2007中的单元格?
3
A
回答
14
以下代码将采用要添加注释的工作表,然后迭代commentsToAdd字典。字典键是单元格引用(即A1),值是要添加的注释文本。
/// <summary>
/// Adds all the comments defined in the commentsToAddDict dictionary to the worksheet
/// </summary>
/// <param name="worksheetPart">Worksheet Part</param>
/// <param name="commentsToAddDict">Dictionary of cell references as the key (ie. A1) and the comment text as the value</param>
public static void InsertComments(WorksheetPart worksheetPart, Dictionary<string, string> commentsToAddDict)
{
if (commentsToAddDict.Any())
{
string commentsVmlXml = string.Empty;
// Create all the comment VML Shape XML
foreach (var commentToAdd in commentsToAddDict)
{
commentsVmlXml += GetCommentVMLShapeXML(GetColumnName(commentToAdd.Key), GetRowIndex(commentToAdd.Key).ToString());
}
// The VMLDrawingPart should contain all the definitions for how to draw every comment shape for the worksheet
VmlDrawingPart vmlDrawingPart = worksheetPart.AddNewPart<VmlDrawingPart>();
using (XmlTextWriter writer = new XmlTextWriter(vmlDrawingPart.GetStream(FileMode.Create), Encoding.UTF8))
{
writer.WriteRaw("<xml xmlns:v=\"urn:schemas-microsoft-com:vml\"\r\n xmlns:o=\"urn:schemas-microsoft-com:office:office\"\r\n xmlns:x=\"urn:schemas-microsoft-com:office:excel\">\r\n <o:shapelayout v:ext=\"edit\">\r\n <o:idmap v:ext=\"edit\" data=\"1\"/>\r\n" +
"</o:shapelayout><v:shapetype id=\"_x0000_t202\" coordsize=\"21600,21600\" o:spt=\"202\"\r\n path=\"m,l,21600r21600,l21600,xe\">\r\n <v:stroke joinstyle=\"miter\"/>\r\n <v:path gradientshapeok=\"t\" o:connecttype=\"rect\"/>\r\n </v:shapetype>"
+ commentsVmlXml + "</xml>");
}
// Create the comment elements
foreach (var commentToAdd in commentsToAddDict)
{
WorksheetCommentsPart worksheetCommentsPart = worksheetPart.WorksheetCommentsPart ?? worksheetPart.AddNewPart<WorksheetCommentsPart>();
// We only want one legacy drawing element per worksheet for comments
if (worksheetPart.Worksheet.Descendants<LegacyDrawing>().SingleOrDefault() == null)
{
string vmlPartId = worksheetPart.GetIdOfPart(vmlDrawingPart);
LegacyDrawing legacyDrawing = new LegacyDrawing() { Id = vmlPartId };
worksheetPart.Worksheet.Append(legacyDrawing);
}
Comments comments;
bool appendComments = false;
if (worksheetPart.WorksheetCommentsPart.Comments != null)
{
comments = worksheetPart.WorksheetCommentsPart.Comments;
}
else
{
comments = new Comments();
appendComments = true;
}
// We only want one Author element per Comments element
if (worksheetPart.WorksheetCommentsPart.Comments == null)
{
Authors authors = new Authors();
Author author = new Author();
author.Text = "Author Name";
authors.Append(author);
comments.Append(authors);
}
CommentList commentList;
bool appendCommentList = false;
if (worksheetPart.WorksheetCommentsPart.Comments != null &&
worksheetPart.WorksheetCommentsPart.Comments.Descendants<CommentList>().SingleOrDefault() != null)
{
commentList = worksheetPart.WorksheetCommentsPart.Comments.Descendants<CommentList>().Single();
}
else
{
commentList = new CommentList();
appendCommentList = true;
}
Comment comment = new Comment() { Reference = commentToAdd.Key, AuthorId = (UInt32Value)0U };
CommentText commentTextElement = new CommentText();
Run run = new Run();
RunProperties runProperties = new RunProperties();
Bold bold = new Bold();
FontSize fontSize = new FontSize() { Val = 8D };
Color color = new Color() { Indexed = (UInt32Value)81U };
RunFont runFont = new RunFont() { Val = "Tahoma" };
RunPropertyCharSet runPropertyCharSet = new RunPropertyCharSet() { Val = 1 };
runProperties.Append(bold);
runProperties.Append(fontSize);
runProperties.Append(color);
runProperties.Append(runFont);
runProperties.Append(runPropertyCharSet);
Text text = new Text();
text.Text = commentToAdd.Value;
run.Append(runProperties);
run.Append(text);
commentTextElement.Append(run);
comment.Append(commentTextElement);
commentList.Append(comment);
// Only append the Comment List if this is the first time adding a comment
if (appendCommentList)
{
comments.Append(commentList);
}
// Only append the Comments if this is the first time adding Comments
if (appendComments)
{
worksheetCommentsPart.Comments = comments;
}
}
}
}
将创建XML VML的形状
Helper方法:
/// <summary>
/// Creates the VML Shape XML for a comment. It determines the positioning of the
/// comment in the excel document based on the column name and row index.
/// </summary>
/// <param name="columnName">Column name containing the comment</param>
/// <param name="rowIndex">Row index containing the comment</param>
/// <returns>VML Shape XML for a comment</returns>
private static string GetCommentVMLShapeXML(string columnName, string rowIndex)
{
string commentVmlXml = string.Empty;
// Parse the row index into an int so we can subtract one
int commentRowIndex;
if (int.TryParse(rowIndex, out commentRowIndex))
{
commentRowIndex -= 1;
commentVmlXml = "<v:shape id=\"" + Guid.NewGuid().ToString().Replace("-", "") + "\" type=\"#_x0000_t202\" style=\'position:absolute;\r\n margin-left:59.25pt;margin-top:1.5pt;width:96pt;height:55.5pt;z-index:1;\r\n visibility:hidden\' fillcolor=\"#ffffe1\" o:insetmode=\"auto\">\r\n <v:fill color2=\"#ffffe1\"/>\r\n" +
"<v:shadow on=\"t\" color=\"black\" obscured=\"t\"/>\r\n <v:path o:connecttype=\"none\"/>\r\n <v:textbox style=\'mso-fit-shape-to-text:true'>\r\n <div style=\'text-align:left\'></div>\r\n </v:textbox>\r\n <x:ClientData ObjectType=\"Note\">\r\n <x:MoveWithCells/>\r\n" +
"<x:SizeWithCells/>\r\n <x:Anchor>\r\n" + GetAnchorCoordinatesForVMLCommentShape(columnName, rowIndex) + "</x:Anchor>\r\n <x:AutoFill>False</x:AutoFill>\r\n <x:Row>" + commentRowIndex + "</x:Row>\r\n <x:Column>" + GetColumnIndexFromName(columnName) + "</x:Column>\r\n </x:ClientData>\r\n </v:shape>";
}
return commentVmlXml;
}
助手找出列索引和注释形状坐标:
/// <summary>
/// Gets the coordinates for where on the excel spreadsheet to display the VML comment shape
/// </summary>
/// <param name="columnName">Column name of where the comment is located (ie. B)</param>
/// <param name="rowIndex">Row index of where the comment is located (ie. 2)</param>
/// <returns><see cref="<x:Anchor>"/> coordinates in the form of a comma separated list</returns>
private static string GetAnchorCoordinatesForVMLCommentShape(string columnName, string rowIndex)
{
string coordinates = string.Empty;
int startingRow = 0;
int startingColumn = GetColumnIndexFromName(columnName).Value;
// From (upper right coordinate of a rectangle)
// [0] Left column
// [1] Left column offset
// [2] Left row
// [3] Left row offset
// To (bottom right coordinate of a rectangle)
// [4] Right column
// [5] Right column offset
// [6] Right row
// [7] Right row offset
List<int> coordList = new List<int>(8) { 0, 0, 0, 0, 0, 0, 0, 0};
if (int.TryParse(rowIndex, out startingRow))
{
// Make the row be a zero based index
startingRow -= 1;
coordList[0] = startingColumn + 1; // If starting column is A, display shape in column B
coordList[1] = 15;
coordList[2] = startingRow;
coordList[4] = startingColumn + 3; // If starting column is A, display shape till column D
coordList[5] = 15;
coordList[6] = startingRow + 3; // If starting row is 0, display 3 rows down to row 3
// The row offsets change if the shape is defined in the first row
if (startingRow == 0)
{
coordList[3] = 2;
coordList[7] = 16;
}
else
{
coordList[3] = 10;
coordList[7] = 4;
}
coordinates = string.Join(",", coordList.ConvertAll<string>(x => x.ToString()).ToArray());
}
return coordinates;
}
/// <summary>
/// Given just the column name (no row index), it will return the zero based column index.
/// Note: This method will only handle columns with a length of up to two (ie. A to Z and AA to ZZ).
/// A length of three can be implemented when needed.
/// </summary>
/// <param name="columnName">Column Name (ie. A or AB)</param>
/// <returns>Zero based index if the conversion was successful; otherwise null</returns>
public static int? GetColumnIndexFromName(string columnName)
{
int? columnIndex = null;
string[] colLetters = Regex.Split(columnName, "([A-Z]+)");
colLetters = colLetters.Where(s => !string.IsNullOrEmpty(s)).ToArray();
if (colLetters.Count() <= 2)
{
int index = 0;
foreach (string col in colLetters)
{
List<char> col1 = colLetters.ElementAt(index).ToCharArray().ToList();
int? indexValue = Letters.IndexOf(col1.ElementAt(index));
if (indexValue != -1)
{
// The first letter of a two digit column needs some extra calculations
if (index == 0 && colLetters.Count() == 2)
{
columnIndex = columnIndex == null ? (indexValue + 1) * 26 : columnIndex + ((indexValue + 1) * 26);
}
else
{
columnIndex = columnIndex == null ? indexValue : columnIndex + indexValue;
}
}
index++;
}
}
return columnIndex;
}
不要完成后忘记保存工作表和工作簿,以便查看更改。
1
许多人会问“如何做到这一点”/“如何做到这一点”使用OpenXML。
最常见的答案是OpenXML很痛苦(我同意)是指第三方库(特别是ClosedXML)。
如果您使用的不是3 - 第三方库,然后我想在此基础上螺纹与一般的提示回答:http://social.msdn.microsoft.com/Forums/office/en-US/81f767d0-15ac-42fe-b122-6c5c02b6c373/cell-color-and-add-comment?forum=oxmlsdk
您可以创建一个名为“Unchanged.xlsx”一个空的工作簿,然后执行您想要反映到Open XML Save中C#代码的自定义作为名为“Changed.xlsx”的已更改工作簿。现在打开Open XML SDK工具,使用比较文件功能,您可以看到对工作簿所做的更改,以及如何通过C#使用Open XML SDK完成这些更改。
有一个选项反映给了你很多关于正在发生的事情的提示代码,见下文(不完全)例如:
因为它是自动生成的代码,它可以被简化/内联/减少。一两个星期后,你会加速。
相关问题
- 1. 使用Open XML SDK 2.0在Excel 2007中添加超链接使用Open XML SDK 2.0
- 2. Open XML SDK 2.0
- 3. Open XML SDK 2.0 - 如何更新电子表格中的单元格?
- 4. Open XML SDK:格式化Excel单元格的一部分
- 5. Excel:使用vba添加评论作者
- 6. 添加评论到宏中的单元格
- 7. 用于Microsoft Office的Open XML SDK 2.0是否支持Office 2007
- 8. 使用Open XML将日期添加到Excel
- 9. 将current_user添加到评论
- 10. 使用硒将图像添加到Excel表单的单元格
- 11. 使用LINQ和Open XML(Excel)
- 12. 如何使用Nokogiri Builder添加评论
- 13. 使用Open XML如何将公式插入到Excel 2010工作表中?
- 14. 使用Open XML将表格添加到PowerPoint幻灯片
- 15. 如何使用TMS Flexcel添加超链接到Excel单元格
- 16. 如何使用POI将单元格注释添加到Excel工作表?
- 17. 如何添加评论框到页面?
- 18. 添加评论/ URL到VCALENDAR
- 19. 如何将NSTableView单元格添加到单元格的填充?
- 20. Open XML SDK 2.0可以按名称访问Excel 2010工作表
- 21. 如何使用open xml访问以前版本的office文件sdk 2.0
- 22. 如何使用closedxml将符号添加到单元格中?
- 23. 如何在C#中使用NPOI Excel添加单元格注释?
- 24. 如何使用python编写excel评论?
- 25. 将评论添加到我的网页
- 26. 使用Open XML Format SDK 2.0创建时不保存文档CTP
- 27. 如何添加到Excel中的当前单元格选择VBA
- 28. Excel将不需要的单元格添加到公式中
- 29. 使用Open XML导出到Excel。但最后一个单元格没有填满
- 30. 过滤后,将单元格的值添加到最大值单元格(Excel VBA)
这将是真正有用的知道哪些库正在使用。另外我无法找到Letters对象是什么。 – Andrew 2011-06-06 04:57:34
适合我! (感谢@amurra)@Andrew - >'''列表字母=新列表(){'A','B','C','D','E','F','G' ,'H','I','J'};'''可以根据需要实现更多字母:) –
2013-12-17 15:01:27
GetColumnName和GetRowIndex方法未定义! – nivs1978 2016-05-31 09:03:21