ChartUpdater.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. // Copyright (c) Microsoft. All rights reserved.
  2. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Xml.Linq;
  9. using DocumentFormat.OpenXml.Packaging;
  10. using OpenXmlPowerTools;
  11. namespace OpenXmlPowerTools
  12. {
  13. public enum ChartDataType
  14. {
  15. Number,
  16. String,
  17. DateTime,
  18. }
  19. // Format Codes
  20. // 0 - general
  21. // 1 - 0
  22. // 2 - 0.00
  23. // 3 - #,##0
  24. // 4 - #,##0.00
  25. // 9 - 0%
  26. // 10 - 0.00%
  27. // 11 - 0.00E+00
  28. // 12 - # ?/?
  29. // 13 - # ??/??
  30. // 14 - mm-dd-yy
  31. // 15 - d-mmm-yy
  32. // 16 - d-mmm
  33. // 17 - mmm-yy
  34. // 18 - h:mm AM/PM
  35. // 19 - h:mm:ss AM/PM
  36. // 20 - h:mm
  37. // 21 - h:mm:ss
  38. // 22 - m/d/yy h:mm
  39. // 37 - #,##0 ;(#,##0)
  40. // 38 - #,##0 ;[Red](#,##0)
  41. // 39 - #,##0.00;(#,##0.00)
  42. // 40 - #,##0.00;[Red](#,##0.00)
  43. // 45 - mm:ss
  44. // 46 - [h]:mm:ss
  45. // 47 - mmss.0
  46. // 48 - ##0.0E+0
  47. // 49 - @
  48. public class ChartData
  49. {
  50. public string[] SeriesNames;
  51. public ChartDataType CategoryDataType;
  52. public int CategoryFormatCode;
  53. public string[] CategoryNames;
  54. public double[][] Values;
  55. }
  56. public class ChartUpdater
  57. {
  58. public static bool UpdateChart(WordprocessingDocument wDoc, string contentControlTag, ChartData chartData)
  59. {
  60. var mainDocumentPart = wDoc.MainDocumentPart;
  61. var mdXDoc = mainDocumentPart.GetXDocument();
  62. var cc = mdXDoc.Descendants(W.sdt)
  63. .FirstOrDefault(sdt => (string)sdt.Elements(W.sdtPr).Elements(W.tag).Attributes(W.val).FirstOrDefault() == contentControlTag);
  64. if (cc != null)
  65. {
  66. var chartRid = (string)cc.Descendants(C.chart).Attributes(R.id).FirstOrDefault();
  67. if (chartRid != null)
  68. {
  69. ChartPart chartPart = (ChartPart)mainDocumentPart.GetPartById(chartRid);
  70. UpdateChart(chartPart, chartData);
  71. var newContent = cc.Elements(W.sdtContent).Elements().Select(e => new XElement(e));
  72. cc.ReplaceWith(newContent);
  73. mainDocumentPart.PutXDocument();
  74. return true;
  75. }
  76. }
  77. return false;
  78. }
  79. public static void UpdateChart(ChartPart chartPart, ChartData chartData)
  80. {
  81. if (chartData.Values.Length != chartData.SeriesNames.Length)
  82. throw new ArgumentException("Invalid chart data");
  83. foreach (var ser in chartData.Values)
  84. {
  85. if (ser.Length != chartData.CategoryNames.Length)
  86. throw new ArgumentException("Invalid chart data");
  87. }
  88. UpdateSeries(chartPart, chartData);
  89. }
  90. private static Dictionary<int, string> FormatCodes = new Dictionary<int, string>()
  91. {
  92. { 0, "general" },
  93. { 1, "0" },
  94. { 2, "0.00" },
  95. { 3, "#,##0" },
  96. { 4, "#,##0.00" },
  97. { 9, "0%" },
  98. { 10, "0.00%" },
  99. { 11, "0.00E+00" },
  100. { 12, "# ?/?" },
  101. { 13, "# ??/??" },
  102. { 14, "mm-dd-yy" },
  103. { 15, "d-mmm-yy" },
  104. { 16, "d-mmm" },
  105. { 17, "mmm-yy" },
  106. { 18, "h:mm AM/PM" },
  107. { 19, "h:mm:ss AM/PM" },
  108. { 20, "h:mm" },
  109. { 21, "h:mm:ss" },
  110. { 22, "m/d/yy h:mm" },
  111. { 37, "#,##0 ;(#,##0)" },
  112. { 38, "#,##0 ;[Red](#,##0)" },
  113. { 39, "#,##0.00;(#,##0.00)" },
  114. { 40, "#,##0.00;[Red](#,##0.00)" },
  115. { 45, "mm:ss" },
  116. { 46, "[h]:mm:ss" },
  117. { 47, "mmss.0" },
  118. { 48, "##0.0E+0" },
  119. { 49, "@" },
  120. };
  121. private static void UpdateSeries(ChartPart chartPart, ChartData chartData)
  122. {
  123. UpdateEmbeddedWorkbook(chartPart, chartData);
  124. XDocument cpXDoc = chartPart.GetXDocument();
  125. XElement root = cpXDoc.Root;
  126. var firstSeries = root.Descendants(C.ser).FirstOrDefault();
  127. var numRef = firstSeries.Elements(C.val).Elements(C.numRef).FirstOrDefault();
  128. string sheetName = null;
  129. var f = (string)firstSeries.Descendants(C.f).FirstOrDefault();
  130. if (f != null)
  131. sheetName = f.Split('!')[0];
  132. // remove all but first series
  133. XName chartType = firstSeries.Parent.Name;
  134. firstSeries.Parent.Elements(C.ser).Skip(1).Remove();
  135. var newSetOfSeries = chartData.SeriesNames
  136. .Select((string sn, int si) =>
  137. {
  138. XElement cat = null;
  139. var oldCat = firstSeries.Elements(C.cat).FirstOrDefault();
  140. if (oldCat == null)
  141. throw new OpenXmlPowerToolsException("Invalid chart markup");
  142. var catHasFormula = oldCat.Descendants(C.f).Any();
  143. if (catHasFormula)
  144. {
  145. XElement newFormula = null;
  146. if (sheetName != null)
  147. newFormula = new XElement(C.f, string.Format("{0}!$A$2:$A${1}", sheetName, chartData.CategoryNames.Length + 1));
  148. if (chartData.CategoryDataType == ChartDataType.String)
  149. {
  150. cat = new XElement(C.cat,
  151. new XElement(C.strRef,
  152. newFormula,
  153. new XElement(C.strCache,
  154. new XElement(C.ptCount, new XAttribute("val", chartData.CategoryNames.Length)),
  155. chartData.CategoryNames.Select((string cn, int ci) =>
  156. {
  157. var newPt = new XElement(C.pt,
  158. new XAttribute("idx", ci),
  159. new XElement(C.v, chartData.CategoryNames[ci]));
  160. return newPt;
  161. }))));
  162. }
  163. else
  164. {
  165. cat = new XElement(C.cat,
  166. new XElement(C.numRef,
  167. newFormula,
  168. new XElement(C.numCache,
  169. new XElement(C.formatCode, FormatCodes[chartData.CategoryFormatCode]),
  170. new XElement(C.ptCount, new XAttribute("val", chartData.CategoryNames.Length)),
  171. chartData.CategoryNames.Select((string cn, int ci) =>
  172. {
  173. var newPt = new XElement(C.pt,
  174. new XAttribute("idx", ci),
  175. new XElement(C.v, chartData.CategoryNames[ci]));
  176. return newPt;
  177. }))));
  178. }
  179. }
  180. else
  181. {
  182. if (chartData.CategoryDataType == ChartDataType.String)
  183. {
  184. cat = new XElement(C.cat,
  185. new XElement(C.strLit,
  186. new XElement(C.ptCount, new XAttribute("val", chartData.CategoryNames.Length)),
  187. chartData.CategoryNames.Select((string cn, int ci) =>
  188. {
  189. var newPt = new XElement(C.pt,
  190. new XAttribute("idx", ci),
  191. new XElement(C.v, chartData.CategoryNames[ci]));
  192. return newPt;
  193. })));
  194. }
  195. else
  196. {
  197. cat = new XElement(C.cat,
  198. new XElement(C.numLit,
  199. new XElement(C.ptCount, new XAttribute("val", chartData.CategoryNames.Length)),
  200. chartData.CategoryNames.Select((string cn, int ci) =>
  201. {
  202. var newPt = new XElement(C.pt,
  203. new XAttribute("idx", ci),
  204. new XElement(C.v, chartData.CategoryNames[ci]));
  205. return newPt;
  206. })));
  207. }
  208. }
  209. XElement newCval = null;
  210. if (sheetName == null)
  211. {
  212. newCval = new XElement(C.val,
  213. new XElement(C.numLit,
  214. new XElement(C.ptCount, new XAttribute("val", chartData.CategoryNames.Length)),
  215. chartData.CategoryNames.Select((string cn, int ci) =>
  216. {
  217. var newPt = new XElement(C.pt,
  218. new XAttribute("idx", ci),
  219. new XElement(C.v, chartData.Values[si][ci]));
  220. return newPt;
  221. })));
  222. }
  223. else
  224. {
  225. newCval = new XElement(C.val,
  226. new XElement(C.numRef,
  227. sheetName != null ?
  228. new XElement(C.f, string.Format("{0}!${2}$2:${2}${1}", sheetName, chartData.CategoryNames.Length + 1, SpreadsheetMLUtil.IntToColumnId(si + 1))) : null,
  229. new XElement(C.numCache,
  230. sheetName != null ? numRef.Descendants(C.formatCode) : null,
  231. new XElement(C.ptCount, new XAttribute("val", chartData.CategoryNames.Length)),
  232. chartData.CategoryNames.Select((string cn, int ci) =>
  233. {
  234. var newPt = new XElement(C.pt,
  235. new XAttribute("idx", ci),
  236. new XElement(C.v, chartData.Values[si][ci]));
  237. return newPt;
  238. }))));
  239. }
  240. var serHasFormula = firstSeries.Descendants(C.f).Any();
  241. XElement tx = null;
  242. if (serHasFormula)
  243. {
  244. XElement newFormula = null;
  245. if (sheetName != null)
  246. newFormula = new XElement(C.f, string.Format("{0}!${1}$1", sheetName, SpreadsheetMLUtil.IntToColumnId(si + 1)));
  247. tx = new XElement(C.tx,
  248. new XElement(C.strRef,
  249. newFormula,
  250. new XElement(C.strCache,
  251. new XElement(C.ptCount, new XAttribute("val", 1)),
  252. new XElement(C.pt,
  253. new XAttribute("idx", 0),
  254. new XElement(C.v, chartData.SeriesNames[si])))));
  255. }
  256. else
  257. {
  258. tx = new XElement(C.tx,
  259. new XElement(C.v, chartData.SeriesNames[si]));
  260. }
  261. XElement newSer = null;
  262. if (chartType == C.area3DChart || chartType == C.areaChart)
  263. {
  264. newSer = new XElement(C.ser,
  265. // common
  266. new XElement(C.idx, new XAttribute("val", si)),
  267. new XElement(C.order, new XAttribute("val", si)),
  268. tx,
  269. firstSeries.Elements(C.spPr),
  270. // CT_AreaSer
  271. firstSeries.Elements(C.pictureOptions),
  272. firstSeries.Elements(C.dPt),
  273. firstSeries.Elements(C.dLbls),
  274. firstSeries.Elements(C.trendline),
  275. firstSeries.Elements(C.errBars),
  276. cat,
  277. newCval,
  278. firstSeries.Elements(C.extLst));
  279. }
  280. else if (chartType == C.bar3DChart || chartType == C.barChart)
  281. {
  282. newSer = new XElement(C.ser,
  283. // common
  284. new XElement(C.idx, new XAttribute("val", si)),
  285. new XElement(C.order, new XAttribute("val", si)),
  286. tx,
  287. firstSeries.Elements(C.spPr),
  288. // CT_BarSer
  289. firstSeries.Elements(C.invertIfNegative),
  290. firstSeries.Elements(C.pictureOptions),
  291. firstSeries.Elements(C.dPt),
  292. firstSeries.Elements(C.dLbls),
  293. firstSeries.Elements(C.trendline),
  294. firstSeries.Elements(C.errBars),
  295. cat,
  296. newCval,
  297. firstSeries.Elements(C.shape),
  298. firstSeries.Elements(C.extLst));
  299. }
  300. else if (chartType == C.line3DChart || chartType == C.lineChart || chartType == C.stockChart)
  301. {
  302. newSer = new XElement(C.ser,
  303. // common
  304. new XElement(C.idx, new XAttribute("val", si)),
  305. new XElement(C.order, new XAttribute("val", si)),
  306. tx,
  307. firstSeries.Elements(C.spPr),
  308. // CT_LineSer
  309. firstSeries.Elements(C.marker),
  310. firstSeries.Elements(C.dPt),
  311. firstSeries.Elements(C.dLbls),
  312. firstSeries.Elements(C.trendline),
  313. firstSeries.Elements(C.errBars),
  314. cat,
  315. newCval,
  316. firstSeries.Elements(C.smooth),
  317. firstSeries.Elements(C.extLst));
  318. }
  319. else if (chartType == C.doughnutChart || chartType == C.ofPieChart || chartType == C.pie3DChart || chartType == C.pieChart)
  320. {
  321. newSer = new XElement(C.ser,
  322. // common
  323. new XElement(C.idx, new XAttribute("val", si)),
  324. new XElement(C.order, new XAttribute("val", si)),
  325. tx,
  326. firstSeries.Elements(C.spPr),
  327. // CT_PieSer
  328. firstSeries.Elements(C.explosion),
  329. firstSeries.Elements(C.dPt),
  330. firstSeries.Elements(C.dLbls),
  331. cat,
  332. newCval,
  333. firstSeries.Elements(C.extLst));
  334. }
  335. else if (chartType == C.surface3DChart || chartType == C.surfaceChart)
  336. {
  337. newSer = new XElement(C.ser,
  338. // common
  339. new XElement(C.idx, new XAttribute("val", si)),
  340. new XElement(C.order, new XAttribute("val", si)),
  341. tx,
  342. firstSeries.Elements(C.spPr),
  343. // CT_SurfaceSer
  344. cat,
  345. newCval,
  346. firstSeries.Elements(C.extLst));
  347. }
  348. if (newSer == null)
  349. throw new OpenXmlPowerToolsException("Unsupported chart type");
  350. int accentNumber = (si % 6) + 1;
  351. newSer = (XElement)UpdateAccentTransform(newSer, accentNumber);
  352. return newSer;
  353. });
  354. firstSeries.ReplaceWith(newSetOfSeries);
  355. chartPart.PutXDocument();
  356. }
  357. private static void UpdateEmbeddedWorkbook(ChartPart chartPart, ChartData chartData)
  358. {
  359. XDocument cpXDoc = chartPart.GetXDocument();
  360. XElement root = cpXDoc.Root;
  361. var firstSeries = root.Descendants(C.ser).FirstOrDefault();
  362. if (firstSeries == null)
  363. return;
  364. var firstFormula = (string)firstSeries.Descendants(C.f).FirstOrDefault();
  365. if (firstFormula == null)
  366. return;
  367. var sheet = firstFormula.Split('!')[0];
  368. var embeddedSpreadsheetRid = (string)root.Descendants(C.externalData).Attributes(R.id).FirstOrDefault();
  369. if (embeddedSpreadsheetRid == null)
  370. return;
  371. var embeddedSpreadsheet = chartPart.GetPartById(embeddedSpreadsheetRid);
  372. if (embeddedSpreadsheet != null)
  373. {
  374. using (SpreadsheetDocument sDoc = SpreadsheetDocument.Open(embeddedSpreadsheet.GetStream(), true))
  375. {
  376. var workbookPart = sDoc.WorkbookPart;
  377. var wbRoot = workbookPart.GetXDocument().Root;
  378. var sheetRid = (string)wbRoot
  379. .Elements(S.sheets)
  380. .Elements(S.sheet)
  381. .Where(s => (string)s.Attribute("name") == sheet)
  382. .Attributes(R.id)
  383. .FirstOrDefault();
  384. if (sheetRid != null)
  385. {
  386. var sheetPart = workbookPart.GetPartById(sheetRid);
  387. var xdSheet = sheetPart.GetXDocument();
  388. var sheetData = xdSheet.Descendants(S.sheetData).FirstOrDefault();
  389. var stylePart = workbookPart.WorkbookStylesPart;
  390. var xdStyle = stylePart.GetXDocument();
  391. int categoryStyleId = 0;
  392. if (chartData.CategoryFormatCode != 0)
  393. categoryStyleId = AddDxfToDxfs(xdSheet, xdStyle, chartData.CategoryFormatCode);
  394. stylePart.PutXDocument();
  395. var firstRow = new XElement(S.row,
  396. new XAttribute("r", "1"),
  397. new XAttribute("spans", string.Format("1:{0}", chartData.SeriesNames.Length + 1)),
  398. new [] { new XElement(S.c,
  399. new XAttribute("r", "A1"),
  400. new XAttribute("t", "str"),
  401. new XElement(S.v,
  402. new XAttribute(XNamespace.Xml + "space", "preserve"),
  403. " "))}
  404. .Concat(
  405. chartData.SeriesNames
  406. .Select((sn, i) => new XElement(S.c,
  407. new XAttribute("r", RowColToString(0, i + 1)),
  408. new XAttribute("t", "str"),
  409. new XElement(S.v, sn)))));
  410. var otherRows = chartData
  411. .CategoryNames
  412. .Select((cn, r) =>
  413. {
  414. var row = new XElement(S.row,
  415. new XAttribute("r", r + 2),
  416. new XAttribute("spans", string.Format("1:{0}", chartData.SeriesNames.Length + 1)),
  417. new[] {
  418. new XElement(S.c,
  419. new XAttribute("r", RowColToString(r + 1, 0)),
  420. categoryStyleId != 0 ? new XAttribute("s", categoryStyleId) : null,
  421. chartData.CategoryDataType == ChartDataType.String ? new XAttribute("t", "str") : null,
  422. new XElement(S.v, cn))
  423. }.Concat(
  424. Enumerable.Range(0, chartData.Values.Length)
  425. .Select((c, ci) =>
  426. {
  427. var cell = new XElement(S.c,
  428. new XAttribute("r", RowColToString(r + 1, ci + 1)),
  429. new XElement(S.v, chartData.Values[ci][r]));
  430. return cell;
  431. })));
  432. return row;
  433. });
  434. var allRows = new[] {
  435. firstRow
  436. }.Concat(otherRows);
  437. var newSheetData = new XElement(S.sheetData,
  438. allRows);
  439. sheetData.ReplaceWith(newSheetData);
  440. sheetPart.PutXDocument();
  441. var tablePartRid = (string)xdSheet
  442. .Root
  443. .Elements(S.tableParts)
  444. .Elements(S.tablePart)
  445. .Attributes(R.id)
  446. .FirstOrDefault();
  447. if (tablePartRid != null)
  448. {
  449. var partTable = sheetPart.GetPartById(tablePartRid);
  450. var xdTablePart = partTable.GetXDocument();
  451. var xaRef = xdTablePart.Root.Attribute("ref");
  452. xaRef.Value = string.Format("A1:{0}", RowColToString(chartData.CategoryNames.Length - 1, chartData.SeriesNames.Length));
  453. var xeNewTableColumns = new XElement(S.tableColumns,
  454. new XAttribute("count", chartData.SeriesNames.Count() + 1),
  455. new[] {
  456. new XElement(S.tableColumn,
  457. new XAttribute("id", 1),
  458. new XAttribute("name", " "))
  459. }.Concat(
  460. chartData.SeriesNames.Select((cn, ci) =>
  461. new XElement(S.tableColumn,
  462. new XAttribute("id", ci + 2),
  463. new XAttribute("name", cn)))));
  464. var xeExistingTableColumns = xdTablePart.Root.Element(S.tableColumns);
  465. if (xeExistingTableColumns != null)
  466. xeExistingTableColumns.ReplaceWith(xeNewTableColumns);
  467. partTable.PutXDocument();
  468. }
  469. }
  470. }
  471. }
  472. }
  473. private static int AddDxfToDxfs(XDocument xdSheet, XDocument xdStyle, int formatCodeToAdd)
  474. {
  475. // add xf to cellXfs
  476. var cellXfs = xdStyle
  477. .Root
  478. .Element(S.cellXfs);
  479. if (cellXfs == null)
  480. {
  481. var cellStyleXfs = xdStyle
  482. .Root
  483. .Element(S.cellStyleXfs);
  484. if (cellStyleXfs != null)
  485. {
  486. cellStyleXfs.AddAfterSelf(
  487. new XElement(S.cellXfs,
  488. new XAttribute("count", 0)));
  489. cellXfs = xdSheet
  490. .Root
  491. .Element(S.cellXfs);
  492. }
  493. }
  494. if (cellXfs == null)
  495. {
  496. var borders = xdStyle
  497. .Root
  498. .Element(S.borders);
  499. if (borders != null)
  500. {
  501. borders.AddAfterSelf(
  502. new XElement(S.cellXfs,
  503. new XAttribute("count", 0)));
  504. cellXfs = xdSheet
  505. .Root
  506. .Element(S.cellXfs);
  507. }
  508. }
  509. if (cellXfs == null)
  510. throw new OpenXmlPowerToolsException("Internal error");
  511. var cnt = (int)cellXfs.Attribute("count");
  512. cnt++;
  513. cellXfs.Attribute("count").Value = cnt.ToString();
  514. cellXfs.Add(
  515. new XElement(S.xf,
  516. new XAttribute("numFmtId", formatCodeToAdd),
  517. new XAttribute("fontId", 0),
  518. new XAttribute("fillId", 0),
  519. new XAttribute("borderId", 0),
  520. new XAttribute("applyNumberFormat", 1)));
  521. return cnt - 1;
  522. }
  523. private static string RowColToString(int row, int col)
  524. {
  525. var str = SpreadsheetMLUtil.IntToColumnId(col) + (row + 1).ToString();
  526. return str;
  527. }
  528. private static object UpdateAccentTransform(XNode node, int accentNumber)
  529. {
  530. XElement element = node as XElement;
  531. if (element != null)
  532. {
  533. if (element.Name == A.schemeClr && (string)element.Attribute("val") == "accent1")
  534. return new XElement(A.schemeClr, new XAttribute("val", "accent" + accentNumber));
  535. return new XElement(element.Name,
  536. element.Attributes(),
  537. element.Nodes().Select(n => UpdateAccentTransform(n, accentNumber)));
  538. }
  539. return node;
  540. }
  541. public static bool UpdateChart(PresentationDocument pDoc, int slideNumber, ChartData chartData)
  542. {
  543. var presentationPart = pDoc.PresentationPart;
  544. var pXDoc = presentationPart.GetXDocument();
  545. var sldIdElement = pXDoc.Root.Elements(P.sldIdLst).Elements(P.sldId).Skip(slideNumber - 1).FirstOrDefault();
  546. if (sldIdElement != null)
  547. {
  548. var rId = (string)sldIdElement.Attribute(R.id);
  549. var slidePart = presentationPart.GetPartById(rId);
  550. var sXDoc = slidePart.GetXDocument();
  551. var chartRid = (string)sXDoc.Descendants(C.chart).Attributes(R.id).FirstOrDefault();
  552. if (chartRid != null)
  553. {
  554. ChartPart chartPart = (ChartPart)slidePart.GetPartById(chartRid);
  555. UpdateChart(chartPart, chartData);
  556. return true;
  557. }
  558. return true;
  559. }
  560. return false;
  561. }
  562. }
  563. }