<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Брайн Джонс: Расширяемый Офис</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/brian_jones_ru/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/brian_jones_ru/feed.xml</link>
    <description>Это зеркало оригинального блога  на русском языке. Вы можете узнать больше об оригинальном блоге по адресу https://blogs.msdn.com/brian_jones/</description>
    <lastBuildDate>Wed, 17 Apr 2019 03:18:57 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Изменения в CTP-версии пакета SDK Open XML версии 2 (апрель 2009 г.)</title>
      <link>https://docs.microsoft.com/archive/blogs/brian_jones_ru/ctp-sdk-open-xml-10</link>
      <pubDate>Thu, 02 Jul 2009 17:41:15 GMT</pubDate>
      <dc:creator><![CDATA[OfficeLocalization]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brian_jones_ru/2009/07/02/ctp-sdk-open-xml-10/</guid>
      <description><![CDATA[Одно из важных изменений, внесенных в CTP-версию пакета SDK Open XML версии 2 (апрель 2009 г.),...]]></description>
      <content:encoded><![CDATA[<P>Одно из <A href="https://blogs.msdn.com/brian_jones/archive/2009/04/08/announcing-the-release-of-the-open-xml-sdk-version-2-april-2009-ctp.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/04/08/announcing-the-release-of-the-open-xml-sdk-version-2-april-2009-ctp.aspx">важных изменений, внесенных в CTP-версию пакета SDK Open XML версии 2 (апрель 2009 г.)</A>, заключается в улучшении <A href="https://blogs.msdn.com/brian_jones/archive/2008/10/06/open-xml-format-sdk-2-0.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2008/10/06/open-xml-format-sdk-2-0.aspx">компонента DOM-модели низкого уровня</A> с целью включения функций, связанных с пакетом обновления 2 (SP2) системы Office 2007. Эта модернизация изменила способ интерпретации некоторых элементов как свойств 1-го класса родительского класса/элемента по отношению к дочернему. Например, SdtProperties теперь не является свойством классов SdtXXX, а интерпретируется как дочерний элемент. Просматривая различные каналы связи с пользователями, сообщения на <A href="https://social.msdn.microsoft.com/Forums/en-US/oxmlsdk/threads" mce_href="https://social.msdn.microsoft.com/Forums/en-US/oxmlsdk/threads">форуме по Open XML SDK</A>, <A href="https://www.openxmldeveloper.org/" mce_href="https://www.openxmldeveloper.org">www.openxmldeveloper.org</A>, а также <A href="https://connect.microsoft.com/feedback/default.aspx?SiteID=589" mce_href="https://connect.microsoft.com/feedback/default.aspx?SiteID=589">сайт SDK Connect</A>, я заметил, что это изменение противоречит некоторым из моих предыдущих записей и примеров кода. В сегодняшней записи я продемонстрирую применение обходного решения этой проблемы и приведу примеры того, как исправить неработающий в настоящее время код и сделать его совместимым с апрельской CTP-версией пакета SDK. </P><H2>SdtBlock не содержит определение для свойств SdtProperties </H2><P>Во многих моих записях о пакете SDK, касающихся программы Word, элементы управления содержимым рассматриваются как семантическая структура. В своих записях я демонстрирую использование элементов управления содержимым для быстрого поиска содержимого или добавления его в конкретные области. Во многих сообщениях используется следующая конструкция фрагмента кода: </P><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SdtBlock</SPAN> sdt = mainPart.Document.Descendants&lt;<SPAN style="COLOR: #2b91af">SdtBlock</SPAN>&gt;() </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.Where(s =&gt; s.SdtProperties.GetFirstChild&lt;<SPAN style="COLOR: #2b91af">Alias</SPAN>&gt;().Val.Value </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.Equals(sdtName)).First();</SPAN> </DIV><P>Если попытаться скомпилировать приведенный выше фрагмент кода в последней CTP-версии пакета SDK, возникнет следующая ошибка компилятора: </P><BLOCKQUOTE><P>'DocumentFormat.OpenXml.Wordprocessing.SdtBlock' does not contain a definition for 'SdtProperties' and no extension method 'SdtProperties' accepting a first argument of type 'DocumentFormat.OpenXml.Wordprocessing.SdtBlock' could be found (are you missing a using directive or an assembly reference?) </P></BLOCKQUOTE><P>Для устранения этой ошибки необходимо получить доступ к SdtProperties как дочернему элементу, а не свойству. Это можно выполнить, используя следующий фрагмент кода: </P><P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SdtBlock</SPAN> sdt = mainPart.Document.Descendants&lt;<SPAN style="COLOR: #2b91af">SdtBlock</SPAN>&gt;() </SPAN></P><P style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.Where(s =&gt; </SPAN></P><P style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">s.GetFirstChild&lt;<SPAN style="COLOR: #2b91af">SdtProperties</SPAN>&gt;().GetFirstChild&lt;<SPAN style="COLOR: #2b91af">Alias</SPAN>&gt;().Val.Value </SPAN></P><P style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.Equals(sdtName)).First(); </SPAN></P><H2>SdtBlock не содержит определение для SdtContentBlock </H2><P>Аналогично случаю с SdtProperties SdtContentBlock перемещен в дочерние элементы и не является больше свойством. Необходимо изменить следующий фрагмент кода: </P><P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">Paragraph</SPAN> p = sdt.SdtContentBlock.GetFirstChild&lt;<SPAN style="COLOR: #2b91af">Paragraph</SPAN>&gt;(); </SPAN></P><P>чтобы он выглядел так: </P><P><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">Paragraph</SPAN> p = sdt.GetFirstChild&lt;<SPAN style="COLOR: #2b91af">SdtContentBlock</SPAN>&gt;().GetFirstChild&lt;<SPAN style="COLOR: #2b91af">Paragraph</SPAN>&gt;(); </SPAN></P><H2>Ссылки на примеры исправленных версий кода или решений </H2><P>Ниже приведены ссылки на исправленные версии прежних решений, функциональность которых была нарушена вследствие внесения изменений в апрельской CTP-версии 2009 года. </P><DIV><TABLE class="" style="BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 287px"><COL style="WIDTH: 160px"></COLGROUP><TBODY vAlign=top><TR style="BACKGROUND: #4f81bd"><TD class="" style="BORDER-RIGHT: medium none; PADDING-RIGHT: 7px; BORDER-TOP: #7ba0cd 1pt solid; PADDING-LEFT: 7px; BORDER-LEFT: #7ba0cd 1pt solid; BORDER-BOTTOM: #7ba0cd 1pt solid"><P><SPAN style="COLOR: white"><STRONG>Решение</STRONG></SPAN></P></TD><TD class="" style="BORDER-RIGHT: #7ba0cd 1pt solid; PADDING-RIGHT: 7px; BORDER-TOP: #7ba0cd 1pt solid; PADDING-LEFT: 7px; BORDER-LEFT: medium none; BORDER-BOTTOM: #7ba0cd 1pt solid"><P><SPAN style="COLOR: white"><STRONG>Ссылка на пример исправленного кода</STRONG></SPAN></P></TD></TR><TR><TD class="" style="PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: #7ba0cd 1pt solid; BORDER-BOTTOM: #7ba0cd 1pt solid"><P><A href="https://blogs.msdn.com/brian_jones/archive/2009/04/01/importing-a-table-from-wordprocessingml-to-spreadsheetml.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/04/01/importing-a-table-from-wordprocessingml-to-spreadsheetml.aspx"><STRONG>Импорт таблиц из Word в Excel </STRONG></A></P></TD><TD class="" style="BORDER-RIGHT: #7ba0cd 1pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-BOTTOM: #7ba0cd 1pt solid"><P><A href="https://zeyadrajabi.members.winisp.net/sourcecode/ImportTableFromWordToExcel(Fixed).zip" mce_href="https://zeyadrajabi.members.winisp.net/sourcecode/ImportTableFromWordToExcel(Fixed).zip">Щелкните здесь</A></P></TD></TR><TR><TD class="" style="PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: #7ba0cd 1pt solid; BORDER-BOTTOM: #7ba0cd 1pt solid"><P><A href="https://blogs.msdn.com/brian_jones/archive/2009/03/13/importing-charts-from-spreadsheets-to-wordprocessing-documents.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/03/13/importing-charts-from-spreadsheets-to-wordprocessing-documents.aspx"><STRONG>Импорт диаграмм из Excel в Word </STRONG></A></P></TD><TD class="" style="BORDER-RIGHT: #7ba0cd 1pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-BOTTOM: #7ba0cd 1pt solid"><P><A href="https://zeyadrajabi.members.winisp.net/sourcecode/ImportChartFromExcelToWord(Fixed).zip" mce_href="https://zeyadrajabi.members.winisp.net/sourcecode/ImportChartFromExcelToWord(Fixed).zip">Щелкните здесь</A></P></TD></TR></TBODY></TABLE></DIV><H2>Отзывы </H2><P>В настоящее время мы ищем пути улучшения поведения пакета SDK и возвращения в него некоторых их утраченных функций, в частности связанных с тем, что некоторые элементы не рассматриваются, как свойства 1<SUP>го</SUP> класса. Следите за обновлениями. </P><P>Хочу воспользоваться случаем и поблагодарить вас за отзывы. Оставайтесь на связи. </P><P>Спасибо. </P><P>Зияд Раджаби (Zeyad Rajabi)</P><img src="https://blogs.msdn.com/aggbug.aspx?PostID=9628506" width="1" height="1"><p>Это локализованная запись блога. Исходную статью можно найти по адресу <a href='https://blogs.msdn.com/brian_jones/archive/2009/05/19/breaking-changes-in-the-open-xml-sdk-v2-april-2009-ctp.aspx'>https://blogs.msdn.com/brian_jones/archive/2009/05/19/breaking-changes-in-the-open-xml-sdk-v2-april-2009-ctp.aspx</a>.]]></content:encoded>
    </item>
    <item>
      <title>Новые средства для решений Open XML</title>
      <link>https://docs.microsoft.com/archive/blogs/brian_jones_ru/open-xml</link>
      <pubDate>Thu, 02 Jul 2009 17:41:09 GMT</pubDate>
      <dc:creator><![CDATA[OfficeLocalization]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brian_jones_ru/2009/07/02/open-xml/</guid>
      <description><![CDATA[Пока я работаю над завершением еще одного решения блога, на этот раз посвященного импорту таблиц из...]]></description>
      <content:encoded><![CDATA[<P>Пока я работаю над завершением еще одного решения блога, на этот раз посвященного импорту таблиц из Word в Excel, мне бы хотелось поделиться сведениями о двух полезных средствах, которыми можно воспользоваться при построении решений на основе Open XML. Первое средство, о котором я собираюсь рассказать, это следующий выпуск PowerTools для Open XML. PowerTools для Open XML представляет собой <A href="https://www.codeplex.com/PowerTools" mce_href="https://www.codeplex.com/PowerTools">проект разработки открытого кода на веб-сайте CodePlex</A>, который полностью основан на версии 1 пакета Open XML SDK. Это средство поддерживает архитектуру конвейеров <A href="https://www.microsoft.com/windowsserver2003/technologies/management/powershell/default.mspx" mce_href="https://www.microsoft.com/windowsserver2003/technologies/management/powershell/default.mspx">PowerShell</A>, предоставляя более 30 командлетов. Рассматривайте командлет как "черный ящик", в который поступает что-то одно, а наружу выходит что-то другое. В случае с PowerTools для Open XML командлеты различными способами создают и изменяют документы Open XML. Например, существуют командлеты для удаления примечаний, принятия отслеживаемых изменений, объединения документов или разделов и даже для создания диаграмм. Самым интересным является то, что ИТ-специалисты и разработчики могут выполнять пакетные сценарии непосредственно в PowerShell. Кстати, данное средство выпущено в качестве открытого кода в соответствии с общедоступной лицензией Майкрософт (Ms-PL), и это означает, что любой может свободно использовать код при создании собственных решений. </P><P>Эрик Уайт (Eric White) опубликовал очень хорошую запись в блоге<A href="https://blogs.msdn.com/ericwhite/archive/2009/03/19/announcing-the-release-of-powertools-for-open-xml-v1-1.aspx" mce_href="https://blogs.msdn.com/ericwhite/archive/2009/03/19/announcing-the-release-of-powertools-for-open-xml-v1-1.aspx">, где описал некоторые подробности версии 1.1 пакета PowerTools для Open XML</A>. В записи приводятся отличные примеры, демонстрирующие объединение разделов документов. В моей предыдущей записи я показал <A href="https://blogs.msdn.com/brian_jones/archive/2008/12/08/the-easy-way-to-assemble-multiple-word-documents.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2008/12/08/the-easy-way-to-assemble-multiple-word-documents.aspx">простой способ объединения документов Word с использованием altChunks</A>. Версия 1.1 пакета PowerTools для Open XML выполняет объединение более сложным образом. Посмотрите и сообщите нам свое мнение. </P><P>Следующее средство, о котором мне бы хотелось поговорить, касается создания решений для документов Office в рамках машинного кода, такого как C++. Пакет Open XML SDK — это отличное средство, но оно привязано к технологиям .NET, т.к. зависит от пространства имен System.IO.Packaging. Как создать решение с использованием машинного кода? Раньше в подобных случаях вам бы пришлось либо создавать собственный уровень перехода от машинного кода к управляемому, или каким-то образом переключать контекст. Хорошая новость: Майкрософт недавно выпустила <A href="https://msdn.microsoft.com/en-us/library/dd371623.aspx" mce_href="https://msdn.microsoft.com/en-us/library/dd371623.aspx">версию Win32 пространства имен System.IO.Packaging</A> под названием Win32 OPC. Вопросы, касающиеся этой технологии, можно размещать на <A href="https://social.msdn.microsoft.com/Forums/en-us/os_opc/threads/" mce_href="https://social.msdn.microsoft.com/Forums/en-us/os_opc/threads/">форуме</A> или в <A href="https://blogs.msdn.com/opc_buzz/" mce_href="https://blogs.msdn.com/opc_buzz/">блоге Win32 OPC</A>. </P><P>Спасибо. </P><P>Зияд Раджаби (Zeyad Rajabi)</P><img src="https://blogs.msdn.com/aggbug.aspx?PostID=9512144" width="1" height="1"><p>Это локализованная запись блога. Исходную статью можно найти по адресу <a href='https://blogs.msdn.com/brian_jones/archive/2009/03/26/more-open-xml-solution-tools.aspx'>https://blogs.msdn.com/brian_jones/archive/2009/03/26/more-open-xml-solution-tools.aspx</a>.]]></content:encoded>
    </item>
    <item>
      <title>Импорт таблицы из WordprocessingML в SpreadsheetML</title>
      <link>https://docs.microsoft.com/archive/blogs/brian_jones_ru/wordprocessingml-spreadsheetml</link>
      <pubDate>Thu, 02 Jul 2009 17:37:24 GMT</pubDate>
      <dc:creator><![CDATA[OfficeLocalization]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brian_jones_ru/2009/07/02/wordprocessingml-spreadsheetml/</guid>
      <description><![CDATA[В предыдущей записи я показал, как импортировать диаграммы из электронных таблиц в текстовый...]]></description>
      <content:encoded><![CDATA[<P>В предыдущей записи я показал, как <A href="https://blogs.msdn.com/brian_jones/archive/2009/03/13/importing-charts-from-spreadsheets-to-wordprocessing-documents.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/03/13/importing-charts-from-spreadsheets-to-wordprocessing-documents.aspx">импортировать диаграммы из электронных таблиц в текстовый документ</A>. Сегодня, как я и обещал в <A href="https://blogs.msdn.com/brian_jones/archive/2009/03/26/more-open-xml-solution-tools.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/03/26/more-open-xml-solution-tools.aspx">прошлой записи</A>, я продемонстрирую импорт таблицы из текстового документа в электронную таблицу. </P><H2>Решение </H2><P>Чтобы импортировать таблицу из текстового документа в электронную таблицу, необходимо выполнить следующие действия: </P><OL><LI>Создать в Word шаблон с элементом управления содержимым, который будет использоваться для разметки области импортируемой таблицы. </LI><LI>Открыть документ Word с помощью пакета Open XML SDK. </LI><LI>Открыть целевую книгу Excel, которая будет содержать импортированную таблицу, с помощью пакета Open XML SDK. </LI><LI>Найти элемент управления содержимым, включающий таблицу Word, и получить доступ к табличному объекту. </LI><LI>Преобразовать таблицу Word в электронную таблицу Excel. Под преобразованием понимается создание вручную таблицы Excel на основе данных таблицы Word. </LI><LI>Добавить раздел определения таблицы в рабочую книгу Excel. </LI><LI>Присвоить определению добавленной таблицы уникальное имя и идентификатор. </LI><LI>Указать диапазон таблицы на основе вставляемых данных. </LI><LI>Добавить сведения для заголовка столбцов в раздел определения таблицы. </LI><LI>Добавить ссылку на стиль в определение таблицы. </LI><LI>Сохранить изменения в рабочей книге Excel. </LI></OL><P>В моей демонстрации будет использоваться <A href="https://go.microsoft.com/fwlink/?LinkId=127912" mce_href="https://go.microsoft.com/fwlink/?LinkId=127912">пакет SDK версии 2</A>. </P><P>Чтобы более наглядно представить изложенный здесь материал, начнем работать со следующим документом Word и таблицей (следует отметить, что таблица содержится в элементе управления содержимым): </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/040209_0044_ImportingaT1.png" mce_src="https://zeyadrajabi.members.winisp.net/040209_0044_ImportingaT1.png"> </P><P>Кроме того, мы будем использовать пустую книгу Excel, содержащую лишь определение стиля для таблиц. </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/040209_0044_ImportingaT2.png" mce_src="https://zeyadrajabi.members.winisp.net/040209_0044_ImportingaT2.png"> </P><P>Если вы хотите отслеживать все этапы работы непосредственно по коду, наше решение можно без труда загрузить <A href="https://zeyadrajabi.members.winisp.net/sourcecode/ImportTableFromWordToExcel.zip" mce_href="https://zeyadrajabi.members.winisp.net/sourcecode/ImportTableFromWordToExcel.zip">здесь</A>. </P><H2>Код </H2><P>Как описано в предыдущем разделе, для выполнения шагов 2 и 3 требуется открыть файлы Word и Excel. Для этого используется следующий фрагмент кода: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Open Word document </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">using</SPAN> (<SPAN style="COLOR: #2b91af">WordprocessingDocument</SPAN> myDoc = <SPAN style="COLOR: #2b91af">WordprocessingDocument</SPAN>.Open(<SPAN style="COLOR: #a31515">"tables.docx"</SPAN>, <SPAN style="COLOR: blue">true</SPAN>)) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">MainDocumentPart</SPAN> mainPart = myDoc.MainDocumentPart; </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Open spreadhseet </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">using</SPAN> (<SPAN style="COLOR: #2b91af">SpreadsheetDocument</SPAN> mySpreadsheet = <SPAN style="COLOR: #2b91af">SpreadsheetDocument</SPAN>.Open(<SPAN style="COLOR: #a31515">"output.xlsx"</SPAN>, <SPAN style="COLOR: blue">true</SPAN>)) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">WorkbookPart</SPAN> workbookPart = mySpreadsheet.WorkbookPart; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Import a specific table from the document into a specific sheet within the spreadsheet </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">ImportWordTable(mainPart, <SPAN style="COLOR: #a31515">"WorldPopulationTable"</SPAN>, workbookPart, <SPAN style="COLOR: #a31515">"Sheet1"</SPAN>); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Я создал универсальный метод ImportWordTable, выполняющий все остальные шаги представленного выше раздела "Решение". Следующий шаг — получение доступа к табличному объекту Word, находящемуся в элементе управления содержимым. Это можно осуществить с помощью следующего кода: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Find the content control that contains the specific table </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SdtBlock</SPAN> sdt = mainPart.Document.Descendants&lt;<SPAN style="COLOR: #2b91af">SdtBlock</SPAN>&gt;() </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.Where(s =&gt; s.SdtProperties.GetFirstChild&lt;<SPAN style="COLOR: #2b91af">Alias</SPAN>&gt;().Val.Value </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.Equals(sdtName)).First(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">Table</SPAN> tbl = sdt.SdtContentBlock.GetFirstChild&lt;<SPAN style="COLOR: #2b91af">Table</SPAN>&gt;();</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Теперь, когда мы получили доступ к таблице Word, нашей следующей задачей является создание таблицы Excel на основе данных, содержащихся в таблице Word. Это можно выполнить, используя следующий фрагмент кода: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">SheetData</SPAN> ConvertWordTableToExcel(<SPAN style="COLOR: #2b91af">Table</SPAN> tbl) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//sheetdata contains data for table </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">Spreadsheet.<SPAN style="COLOR: #2b91af">SheetData</SPAN> sheetdata = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">SheetData</SPAN>(); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//For every row in my Word table we need to create a row in Excel </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: #2b91af">TableRow</SPAN> row <SPAN style="COLOR: blue">in</SPAN> tbl.Descendants&lt;<SPAN style="COLOR: #2b91af">TableRow</SPAN>&gt;()) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">numRows++; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">Spreadsheet.<SPAN style="COLOR: #2b91af">Row</SPAN> sheetRow = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">Row</SPAN>(); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//For every Word cell create an Excel cell </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: #2b91af">TableCell</SPAN> cell <SPAN style="COLOR: blue">in</SPAN> row.Descendants&lt;<SPAN style="COLOR: #2b91af">TableCell</SPAN>&gt;()) </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">Spreadsheet.<SPAN style="COLOR: #2b91af">Cell</SPAN> sheetCell = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">Cell</SPAN>(); </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">string</SPAN> textValue = cell.InnerText; </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">double</SPAN> numValue; </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Check to see if value is a number rather than a string </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//First row should be strings because I am going to create a table </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">if</SPAN> ((numRows != 1) &amp;&amp; (<SPAN style="COLOR: #2b91af">Double</SPAN>.TryParse(textValue, System.Globalization.<SPAN style="COLOR: #2b91af">NumberStyles</SPAN>.Any, <SPAN style="COLOR: blue">null</SPAN>, <SPAN style="COLOR: blue">out</SPAN> numValue))) </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">Spreadsheet.<SPAN style="COLOR: #2b91af">CellValue</SPAN> v = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">CellValue</SPAN>(); </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">textValue = numValue.ToString(); </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">v.Text = textValue; </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">sheetCell.Append(v); </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">else</SPAN> <SPAN style="COLOR: green">//value is a string </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">sheetCell.DataType = Spreadsheet.<SPAN style="COLOR: #2b91af">CellValues</SPAN>.InlineString; </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">Spreadsheet.<SPAN style="COLOR: #2b91af">InlineString</SPAN> inlineString = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">InlineString</SPAN>(); </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">Spreadsheet.<SPAN style="COLOR: #2b91af">Text</SPAN> t = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">Text</SPAN>(); </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">t.Text = textValue; </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">inlineString.Append(t); </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">sheetCell.Append(inlineString); </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Need to keep track of column headers for the table </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//definitions part </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">if</SPAN> (numRows == 1) </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">colHeaders.Add(textValue); </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">sheetRow.Append(sheetCell); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">sheetdata.Append(sheetRow); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">return</SPAN> sheetdata; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Представленный выше фрагмент кода создает для каждой строки и ячейки таблицы Word строку и ячейку в электронной таблице Excel. Ячейка электронной таблицы немного отличается от ячейки таблицы Word, поскольку в ячейке электронной таблицы содержится определение типа содержимого. В приведенном примере у нас два типа ячеек. </P><OL><LI>Текст. </LI><LI>Число. </LI></OL><P>Поскольку решение предполагает создание таблицы Excel, необходимо помнить еще о некоторых вещах. Во-первых, следует убедиться, что первая строка таблицы содержит только текстовые ячейки, поскольку она будет определена как строка заголовка. Во-вторых, необходимо отслеживать текст в строке заголовка, поскольку он будет повторно использован в разделе определений таблицы. </P><P>В конце этого шага мы создали допустимую электронную таблицу Excel, содержащую все данные из таблицы Word. </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/040209_0044_ImportingaT3.png" mce_src="https://zeyadrajabi.members.winisp.net/040209_0044_ImportingaT3.png"> </P><P>На этом работа могла бы быть закончена, но мы можем улучшить вывод, отформатировав данные в виде таблицы. </P><P>Вернувшись к шагу 6 в разделе "Решение", необходимо добавить ссылку на раздел определений таблицы на листе, содержащем данные. Ниже представлен фрагмент кода, создающий новый раздел определения таблицы и добавляющий ссылку на этот раздел с листа, содержащего табличные данные. </P><DIV style="MARGIN-LEFT: 30pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Add the table definitions part to make the imported table look like a table </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">TableDefinitionPart</SPAN> tableDefPart = worksheetPart.AddNewPart&lt;<SPAN style="COLOR: #2b91af">TableDefinitionPart</SPAN>&gt;(relId); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Reference the added table part </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">Spreadsheet.<SPAN style="COLOR: #2b91af">TableParts</SPAN> tableParts = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">TableParts</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">Spreadsheet.<SPAN style="COLOR: #2b91af">TablePart</SPAN> tablePart = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">TablePart</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tablePart.Id = relId; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableParts.Append(tablePart); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">worksheetPart.Worksheet.Append(tableParts);</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Последняя серия шагов направлена на создание соответствующего кода XML в новом разделе определений таблицы. Чтобы все работало должным образом, каждое определение таблицы должно иметь уникальное имя, идентификатор, отображаемое имя и ссылку на диапазон данных. Эти задачи выполняются в следующем фрагменте кода: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">int</SPAN> id = 1; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableDefPart.Table = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">Table</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableDefPart.Table.Id = 1; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableDefPart.Table.Name = <SPAN style="COLOR: #a31515">"Table1"</SPAN>; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableDefPart.Table.DisplayName = <SPAN style="COLOR: #a31515">"Table1"</SPAN>; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">char</SPAN> endCol = <SPAN style="COLOR: #a31515">'A'</SPAN>; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Note that this approach is good for columns up to Z </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Excel can contain more columns, but 26 columns should </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//be good enough for this demo </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">for</SPAN> (<SPAN style="COLOR: blue">int</SPAN> i = 1; i &lt; numCols; i++) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">endCol++; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Specify the range of the table </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">string</SPAN> reference = <SPAN style="COLOR: #a31515">"A1:"</SPAN> + endCol + numRows; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableDefPart.Table.Reference = reference;</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Одним из преимуществ таблицы Excel перед таблицей Word является то, что таблица Excel позволяет фильтровать значения в пределах столбца. Эта функция довольно легко добавляется в таблицу с помощью следующего кода: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Make sure the table has the ability to filter </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">Spreadsheet.<SPAN style="COLOR: #2b91af">AutoFilter</SPAN> autoFilter = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">AutoFilter</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">autoFilter.Reference = reference; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">Spreadsheet.<SPAN style="COLOR: #2b91af">TableColumns</SPAN> tableColumns = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">TableColumns</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableColumns.Count = numCols;</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Теперь добавим сведения для заголовка таблицы. </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Add the column headers to the table definition part </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: blue">string</SPAN> s <SPAN style="COLOR: blue">in</SPAN> colHeaders) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">Spreadsheet.<SPAN style="COLOR: #2b91af">TableColumn</SPAN> tableColumn = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">TableColumn</SPAN>(); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableColumn.Id = (<SPAN style="COLOR: blue">uint</SPAN>)id; </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableColumn.Name = s; </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">id++; </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableColumns.Append(tableColumn); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Почти готово! Теперь поработаем над внешним видом таблицы, применив стиль. После применения стиля можно объединить все необходимые элементы и сохранить изменения. Это можно выполнить, используя следующий код: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Apply a nice table style (contained within my template) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">Spreadsheet.<SPAN style="COLOR: #2b91af">TableStyleInfo</SPAN> tableStyleInfo = <SPAN style="COLOR: blue">new</SPAN> Spreadsheet.<SPAN style="COLOR: #2b91af">TableStyleInfo</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableStyleInfo.Name = <SPAN style="COLOR: #a31515">"TableStyleMedium9"</SPAN>; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableStyleInfo.ShowRowStripes = <SPAN style="COLOR: blue">true</SPAN>; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableDefPart.Table.Append(autoFilter, tableColumns, tableStyleInfo); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableDefPart.Table.Save();</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><H2>Заключение </H2><P>Собрав вместе все показанные фрагменты и запустив итоговый код, мы получим рабочую книгу Excel, содержащую импортированную из документа Word таблицу. </P><P>Вот снимок экрана с полученной книгой (обратите внимание на возможность фильтрации): </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/040209_0044_ImportingaT4.png" mce_src="https://zeyadrajabi.members.winisp.net/040209_0044_ImportingaT4.png"> </P><P>Зияд Раджаби (Zeyad Rajabi)</P><img src="https://blogs.msdn.com/aggbug.aspx?PostID=9528255" width="1" height="1"><p>Это локализованная запись блога. Исходную статью можно найти по адресу <a href='https://blogs.msdn.com/brian_jones/archive/2009/04/01/importing-a-table-from-wordprocessingml-to-spreadsheetml.aspx'>https://blogs.msdn.com/brian_jones/archive/2009/04/01/importing-a-table-from-wordprocessingml-to-spreadsheetml.aspx</a>.]]></content:encoded>
    </item>
    <item>
      <title>Переходы по дереву DOM-модели Open XML</title>
      <link>https://docs.microsoft.com/archive/blogs/brian_jones_ru/dom-open-xml</link>
      <pubDate>Thu, 02 Jul 2009 17:37:23 GMT</pubDate>
      <dc:creator><![CDATA[OfficeLocalization]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brian_jones_ru/2009/07/02/dom-open-xml/</guid>
      <description><![CDATA[В последних записях я уделял внимание демонстрации решений для реальных, повседневных сценариев....]]></description>
      <content:encoded><![CDATA[<P>В последних записях я уделял внимание демонстрации решений для реальных, повседневных сценариев. Сегодня я сменю темп и продолжу <A href="https://blogs.msdn.com/brian_jones/archive/2009/01/12/open-xml-sdk-the-basics.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/01/12/open-xml-sdk-the-basics.aspx">обсуждение Али</A>, посвященное основным сведениям о пакете Open XML SDK. В этой записи мы рассмотрим основные методы перехода по дереву DOM-модели Open XML с помощью пакета Open XML SDK. </P><H2>И снова, это всего лишь XML... </H2><P>Мы разработали <A href="https://blogs.msdn.com/brian_jones/archive/2008/10/14/open-xml-sdk-2-0-architecture.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2008/10/14/open-xml-sdk-2-0-architecture.aspx">DOM-модель низкого уровня для Open XML</A> в качестве XML-оболочки схем Open XML. Иными словами, этот компонент пакета SDK позволяет работать непосредственно со строго типизированными объектами и классами, представляющими основные узлы XML. По сути, даже используя SDK, вы продолжаете работать только с XML. </P><P>Существует несколько традиционных технологий, позволяющих выполнять переход на более низкий уровень дерева XML. При разработке Open XML SDK мы хотели включить в пакет функции DOM и LINQ, чтобы предоставить пользователям богатый набор средств. Компонент DOM-модели низкого уровня — это попытка объединить концепции API-интерфейса DOM-модели .NET и LINQ в XML. Рассмотрим некоторые из этих концепций. </P><H2>Переход на более низкий уровень дерева XML </H2><P>Одной из наиболее распространенных задач при чтении XML-файлов является переход на более низкий уровень конкретного узла XML, например корневого. Обычно переход вниз требуется при поиске. Допустим, вам необходимо изменить содержимое всех строк таблицы в документе. Одним их способов выполнения такого сценария является переход на более низкий уровень, начиная с корневого элемента документа с нахождением таблицы и элементов строк таблицы до тех пор, пока не будет достигнут конец документа. Open XML SDK упрощает решение этой задачи. </P><P>Как уже упоминалось в <A href="https://blogs.msdn.com/brian_jones/archive/2009/01/12/open-xml-sdk-the-basics.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/01/12/open-xml-sdk-the-basics.aspx">записи Али</A>, все элементы Open XML основываются на абстрактном классе OpenXMLElement. Класс OpenXMLElement предоставляет следующие методы и свойства для перехода вниз в пределах DOM-модели: </P><OL><LI><SPAN style="COLOR: #1f497d">OpenXMLElement </SPAN><STRONG>FirstChild </STRONG>{ get; } </LI><LI><SPAN style="COLOR: #1f497d">OpenXMLElement </SPAN><STRONG>LastChild </STRONG>{ get; } </LI><LI><SPAN style="COLOR: #1f497d">IEnumerable</SPAN>&lt;<SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN>&gt; <STRONG>Elements </STRONG>() </LI><LI><SPAN style="COLOR: #1f497d">OpenXmlElementList </SPAN><STRONG>ChildElements </STRONG>{ get; }. </LI><LI><SPAN style="COLOR: #1f497d">IEnumerable</SPAN>&lt;<SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN>&gt; <STRONG>GetEnumerator </STRONG>() </LI><LI><SPAN style="COLOR: #1f497d">IEnumerable</SPAN>&lt;<SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN>&gt; <STRONG>Descendants </STRONG>() </LI></OL><P>Между перечисленными подходами существуют некоторые ключевые различия. Для более наглядного представления этих различий представьте, что вам необходимо выполнить чтение элементов в объекте Table, который содержит свойства таблицы, сведения о сетке таблицы и содержимое строк: </P><DIV style="MARGIN-LEFT: 25px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">&lt;</SPAN><SPAN style="COLOR: #a31515">w:tbl</SPAN><SPAN style="COLOR: blue">&gt; </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 50px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">&lt;</SPAN><SPAN style="COLOR: #a31515">w:tblPr</SPAN><SPAN style="COLOR: blue">&gt; </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 75px"><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV style="MARGIN-LEFT: 50px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">w:tblPr</SPAN><SPAN style="COLOR: blue">&gt; </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 50px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">&lt;</SPAN><SPAN style="COLOR: #a31515">w:tblGrid</SPAN><SPAN style="COLOR: blue">&gt; </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 75px"><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV style="MARGIN-LEFT: 50px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">w:tblGrid</SPAN><SPAN style="COLOR: blue">&gt; </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 50px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">&lt;</SPAN><SPAN style="COLOR: #a31515">w:tr</SPAN><SPAN style="COLOR: blue">&gt; </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 75px"><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV style="MARGIN-LEFT: 50px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">w:tr</SPAN><SPAN style="COLOR: blue">&gt; </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 50px"><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV style="MARGIN-LEFT: 50px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">&lt;</SPAN><SPAN style="COLOR: #a31515">w:tr</SPAN><SPAN style="COLOR: blue">&gt; </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 75px"><SPAN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV style="MARGIN-LEFT: 50px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">w:tr</SPAN><SPAN style="COLOR: blue">&gt; </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 25px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">&lt;/</SPAN><SPAN style="COLOR: #a31515">w:tbl</SPAN><SPAN style="COLOR: blue">&gt;</SPAN></SPAN> </DIV><P>Методы FirstChild() и LastChild() довольно прямолинейны. Они возвращают первый и последний дочерние элементы соответственно. </P><P>Метод Elements() позволяет выполнять чтение всех дочерних элементов объекта Table, используя следующий фрагмент кода: </P><DIV style="MARGIN-LEFT: 25px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: #2b91af">OpenXmlElement</SPAN> el <SPAN style="COLOR: blue">in</SPAN> tbl.Elements()) </SPAN></DIV><DIV style="MARGIN-LEFT: 25px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 50px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: green">//DO SOMETHING </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 25px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><P>Свойство ChildElements немного отличается от остальных. При его непосредственном вызове, подобно tbl.ChildElements, оно возвращает список элементов Open XML, являющихся дочерними элементами таблицы. В этом отношении оно эквивалентно свойству tbl.Elements(). Отличие свойства ChildElements от Elements() заключается в возможности указания индекса. Например, если требуется четвертый дочерний элемент объекта Table, вы вызываете свойство tbl.ChildElements[3]. </P><P>Подобно двум другим подходам, метод GetEnumerator() обеспечивает поддержку итерации по всем дочерним элементам. </P><P>Метод Descendants(), наоборот, позволяет выполнять итерацию по всем дочерним элементам и потомкам конкретного узла. Используя объект Table в качестве примера и вызвав метод Descendants(), можно не только просмотреть строки таблицы, но и ячейки внутри строк. </P><P>Вместо выполнения итерации по всем дочерним элементам более распространенный сценарий выполняет поиск дочерних элементов или потомков конкретного типа класса. Допустим, необходимо найти элементы строки таблицы под объектом Table. Вместо выполнения итерации по всем дочерним элементам с проверкой, является ли каждый из них строкой таблицы, можно просто воспользоваться следующими методами: </P><OL><LI><SPAN style="COLOR: #1f497d">IEnumerable</SPAN>&lt;<SPAN style="COLOR: #1f497d">T</SPAN>&gt; <STRONG>Elements&lt;T&gt; </STRONG>()where T : <SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN> </LI><LI><SPAN style="COLOR: #1f497d">IEnumerable</SPAN>&lt;<SPAN style="COLOR: #1f497d">T</SPAN>&gt; <STRONG>Descendants&lt;T&gt; </STRONG>()where T : <SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN> </LI><LI><SPAN style="COLOR: #1f497d">T </SPAN><STRONG>GetFirstChild&lt;T&gt; </STRONG>()where T : <SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN> </LI></OL><P>Первые два метода возвращают только элементы типа T или производные от T. Для поиска в приведенном выше примере всех строк таблицы необходимо использовать следующий фрагмент кода: </P><DIV style="MARGIN-LEFT: 25px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: #2b91af">TableRow</SPAN> tr <SPAN style="COLOR: blue">in</SPAN> tbl.Elements&lt;<SPAN style="COLOR: #2b91af">TableRow</SPAN>&gt;()) </SPAN></DIV><DIV style="MARGIN-LEFT: 25px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 50px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: green">//DO SOMETHING </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 25px"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN> </DIV><P>Последний метод позволяет получить первый дочерний элемент, принадлежащий заданному типу. В данном случае для получения первой строки я бы использовал tbl.GetFirstChild&lt;TableRow&gt;(). </P><H2>Переход на более высокий уровень дерева XML </H2><P>Подобно переходу на более низкий уровень дерева XML можно переходить и на более высокий. Эта функция обеспечивает гибкость при переходе по дереву DOM-модели. Допустим, вы выполняете поиск конкретного текста и вам необходимо получить дополнительные сведения о его контексте, например содержится ли текст в таблице. Для выполнения этого сценария необходимо выполнить переход вверх по дереву. Пакет Open XML SDK предоставляет следующие методы и свойства для перехода на более высокий уровень в DOM-модели: </P><OL><LI><SPAN style="COLOR: #1f497d">OpenXmlElement </SPAN><STRONG>Parent</STRONG><SPAN style="COLOR: #1f497d"> </SPAN></LI><LI><SPAN style="COLOR: #1f497d">IEnumerable</SPAN>&lt;<SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN>&gt; <STRONG>Ancestors </STRONG>() </LI><LI><SPAN style="COLOR: #1f497d">IEnumerable</SPAN>&lt; T &gt; <STRONG>Ancestors&lt;T&gt; </STRONG>() where T : <SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN> </LI></OL><P>Свойство Parent возвращает непосредственный родительский элемент конкретного узла. При вызове свойства Parent для объекта строки таблицы возвращается объект Table. </P><P>Методы Ancestors() действуют подобно методам Descendants(), кроме того, что выполняют переход вверх, а не вниз. </P><H2>Переход по горизонтали в пределах дерева XML </H2><P>Что делать, если необходимо выполнить переход по дереву XML по горизонтали с просмотром одноуровневых элементов? Open XML SDK может справиться и с этим. В пакете Open XML SDK предусмотрены следующие методы для выполнения таких сценариев: </P><OL><LI><SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN> <STRONG>PreviousSibling</STRONG> () </LI><LI><SPAN style="COLOR: #1f497d">T</SPAN> <STRONG>PreviousSibling&lt;T&gt; </STRONG>() where T : <SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN> </LI><LI><SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN> <STRONG>NextSibling</STRONG> () </LI><LI><SPAN style="COLOR: #1f497d">T</SPAN> <STRONG>NextSibling&lt;T&gt; </STRONG>() where T : <SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN> </LI><LI><SPAN style="COLOR: #1f497d">IEnumerable</SPAN>&lt;<SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN>&gt;<STRONG> ElementsBefore </STRONG>() </LI><LI><SPAN style="COLOR: #1f497d">IEnumerable</SPAN>&lt;<SPAN style="COLOR: #1f497d">OpenXmlElement</SPAN>&gt;<STRONG> ElementsAfter</STRONG> () </LI></OL><P>Первые четыре метода возвращают ближайшие элементы того же уровня, расположенные до или после текущего элемента, а остальные методы перечисляют все одноуровневые элементы, расположенные до или после элемента под тем же родительским элементом. </P><H2>Заключение </H2><P>Надеюсь, в этой публикации мне удалось продемонстрировать некоторые распространенные способы перехода по дереву DOM-модели Open XML. Благодаря этим функциям вы можете выполнять поиск необходимых элементов, используя всего несколько строк кода. </P><P>Зияд Раджаби (Zeyad Rajabi)</P><img src="https://blogs.msdn.com/aggbug.aspx?PostID=9381525" width="1" height="1"><p>Это локализованная запись блога. Исходную статью можно найти по адресу <a href='https://blogs.msdn.com/brian_jones/archive/2009/01/28/traversing-in-the-open-xml-dom.aspx'>https://blogs.msdn.com/brian_jones/archive/2009/01/28/traversing-in-the-open-xml-dom.aspx</a>.]]></content:encoded>
    </item>
    <item>
      <title>Копирование листа в пределах книги</title>
      <link>https://docs.microsoft.com/archive/blogs/brian_jones_ru/63</link>
      <pubDate>Thu, 02 Jul 2009 17:37:21 GMT</pubDate>
      <dc:creator><![CDATA[OfficeLocalization]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brian_jones_ru/2009/07/02/63/</guid>
      <description><![CDATA[В прошлой записи о повторно используемых методах работы с WordprocessingML я обещал рассказать о...]]></description>
      <content:encoded><![CDATA[<P>В прошлой записи о <A href="https://blogs.msdn.com/brian_jones/archive/2009/02/13/reusable-methods-for-manipulating-paragraphs-in-wordprocessingml.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/02/13/reusable-methods-for-manipulating-paragraphs-in-wordprocessingml.aspx">повторно используемых методах работы с WordprocessingML</A> я обещал рассказать о том, как выполняется копирование листа в пределах книги. Следует заметить, что в этой записи речь пойдет о копировании листа в пределах одного пакета. Возможно, в будущем я напишу и о том, как импортировать и экспортировать листы между книгами. </P><H2>Решение </H2><P>Чтобы скопировать лист в пределах книги, необходимо выполнить следующие действия: </P><OL><LI>Открыть документ электронной таблицы с помощью пакета Open XML SDK. </LI><LI>Получить доступ к главному разделу книги, из которого можно получить доступ к ряду взаимосвязанных разделов, таких как отдельные листы. </LI><LI>Получить доступ к листу, который необходимо скопировать. </LI><LI>Создать клон найденного листа и всех связанных с ним разделов и добавить этот клон и все связанные с ним разделы в книгу. </LI><LI>Выполнить очистку для обеспечения правильной работы таблиц, представлений и пр. </LI><LI>Добавить ссылку на созданный лист в список листов главного раздела книги. </LI><LI>Сохранить изменения в книге. </LI></OL><P>В моей демонстрации будет использоваться <A href="https://go.microsoft.com/fwlink/?LinkId=127912" mce_href="https://go.microsoft.com/fwlink/?LinkId=127912">пакет SDK версии 2</A>. </P><P>Чтобы более наглядно представить изложенный здесь материал, начнем работать с довольно сложной рабочей книгой, содержащей данные, условное форматирование, фигуру, изображение, таблицу, рисунок SmartArt и диаграмму. Книга включает три листа и имеет следующий вид: </P><P><IMG alt="Снимок экрана с примером книги Excel" src="https://zeyadrajabi.members.winisp.net/screen1.png"> </P><P>Если вы хотите отслеживать все этапы работы непосредственно по коду, наше решение можно без труда загрузить <A href="https://zeyadrajabi.members.winisp.net/sourcecode/CopyWorksheet.zip" mce_href="https://zeyadrajabi.members.winisp.net/sourcecode/CopyWorksheet.zip">здесь</A>. </P><H2>Сравнение методов AddPart&lt;T&gt;() и AddNewPart&lt;T&gt;() </H2><P>Перед подробным рассмотрением перечисленных выше шагов я хочу рассказать о разнице между двумя методами, представленными в пакете SDK для добавления разделов в пакет Open XML. Метод AddNewPart выполняет следующие действия: </P><OL><LI>Создает пустой раздел типа T и добавляет его в пакет. </LI><LI>После создания раздела добавляет ссылку из ссылающегося раздела на новый раздел. </LI></OL><P>Следующим шагом после добавления нового раздела с помощью этого метода обычно является вызов метода FeedData() для направления данных в этот раздел. </P><P>Метод AddPart выполняет следующие действия: </P><OL><LI>Если добавленный раздел еще не включен в пакет, метод добавит этот раздел и все связанные с ним разделы в пакет. Таким образом, если вы добавляете раздел А, а раздел А ссылается на раздел Б, который в свою очередь ссылается на раздел В, то при вызове этого метода, произойдет добавление разделов А, Б и В. Кроме этого, метод обеспечивает сохранность отношений добавляемых разделов. Эта функция чем-то напоминает импорт многоуровневого клона. </LI><LI>Если добавляемый раздел уже присутствует в пакете, метод добавит ссылку из ссылающегося раздела на раздел, уже присутствующий в пакете. Например, разделы А и Б присутствуют в пакете, но раздел А не ссылается на раздел Б. При вызове данного метода добавляется ссылка из раздела А на раздел Б, если это поддерживается форматом Open XML. </LI></OL><P>Как видно, метод AddPart обладает более широкими возможностями, чем простой метод AddNewPart. Вы поймете его преимущества, когда я покажу, как выполняется создание клона раздела в пределах пакета. </P><H2>Код </H2><P>Как описано выше в разделе "Решение", для выполнения первых трех шагов требуется открыть книгу и получить доступ к листу, который необходимо скопировать. Для этого используются следующие фрагменты кода: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> CopySheet(<SPAN style="COLOR: blue">string</SPAN> filename, <SPAN style="COLOR: blue">string</SPAN> sheetName, <SPAN style="COLOR: blue">string</SPAN> clonedSheetName) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Open workbook </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">using</SPAN> (<SPAN style="COLOR: #2b91af">SpreadsheetDocument</SPAN> mySpreadsheet = <SPAN style="COLOR: #2b91af">SpreadsheetDocument</SPAN>.Open(filename, <SPAN style="COLOR: blue">true</SPAN>)) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">WorkbookPart</SPAN> workbookPart = mySpreadsheet.WorkbookPart; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Get the source sheet to be copied </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">WorksheetPart</SPAN> sourceSheetPart = GetWorkSheetPart(workbookPart, sheetName); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">...<SPAN style="COLOR: green"> </SPAN></SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Ниже приведен фрагмент кода, необходимый для получения доступа к разделу листа на основе имени листа. </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: #2b91af">WorksheetPart</SPAN> GetWorkSheetPart(<SPAN style="COLOR: #2b91af">WorkbookPart</SPAN> workbookPart, <SPAN style="COLOR: blue">string</SPAN> sheetName) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Get the relationship id of the sheetname </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">string</SPAN> relId = workbookPart.Workbook.Descendants&lt;<SPAN style="COLOR: #2b91af">Sheet</SPAN>&gt;() </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.Where(s =&gt; s.Name.Value.Equals(sheetName)) </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.First() </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.Id; </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">return</SPAN> (<SPAN style="COLOR: #2b91af">WorksheetPart</SPAN>)workbookPart.GetPartById(relId); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Теперь, когда мы получили доступ к разделу листа, который необходимо скопировать, надо выполнить задачу создания клона. Именно здесь я и воспользуюсь преимуществом метода AddPart. Возможно, в будущей сборке пакета SDK будет включен метод клонирования для разделов. Как уже было сказано выше, метод AddPart отлично подходит для добавления раздела и всех разделов, на которые он ссылается. К сожалению, эта функция работает только при добавлении разделов, которые еще не присутствуют в пакете. Для обхода этого ограничения мы можем просто вызвать метод AddPart для временной книги, а затем снова вызвать метод AddPart в главной книге. Эта задача выполняется с помощью следующего кода: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> CopySheet(<SPAN style="COLOR: blue">string</SPAN> filename, <SPAN style="COLOR: blue">string</SPAN> sheetName, <SPAN style="COLOR: blue">string</SPAN> clonedSheetName) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Take advantage of AddPart for deep cloning </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SpreadsheetDocument</SPAN> tempSheet = <SPAN style="COLOR: #2b91af">SpreadsheetDocument</SPAN>.Create(<SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">MemoryStream</SPAN>(), mySpreadsheet.DocumentType); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">WorkbookPart</SPAN> tempWorkbookPart = tempSheet.AddWorkbookPart(); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">WorksheetPart</SPAN> tempWorksheetPart = tempWorkbookPart.AddPart&lt;<SPAN style="COLOR: #2b91af">WorksheetPart</SPAN>&gt;(sourceSheetPart); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Add cloned sheet and all associated parts to workbook </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">WorksheetPart</SPAN> clonedSheet = workbookPart.AddPart&lt;<SPAN style="COLOR: #2b91af">WorksheetPart</SPAN>&gt;(tempWorksheetPart); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">...<SPAN style="COLOR: green"> </SPAN></SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>К этому моменту мы успешно клонировали лист и добавили его и связанные с ним разделы в книгу. Почти все готово... </P><P>Теперь необходимо выполнить некоторые задачи по очистке. Например, SpreadsheetML требует, чтобы у каждой таблицы были уникальное имя и идентификатор. Кроме этого, действительно, должен быть только один лист, установленный как главное представление. В следующем коде показано, как выполнить очистку: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> CopySheet(<SPAN style="COLOR: blue">string</SPAN> filename, <SPAN style="COLOR: blue">string</SPAN> sheetName, <SPAN style="COLOR: blue">string</SPAN> clonedSheetName) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Table definition parts are somewhat special and need unique ids...so let's make an id based on count </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">int</SPAN> numTableDefParts = sourceSheetPart.GetPartsCountOfType&lt;<SPAN style="COLOR: #2b91af">TableDefinitionPart</SPAN>&gt;(); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableId = numTableDefParts; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Clean up table definition parts (tables need unique ids) </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">if</SPAN> (numTableDefParts != 0) </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">FixupTableParts(clonedSheet, numTableDefParts); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//There should only be one sheet that has focus </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">CleanView(clonedSheet); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Очистка представления предполагает удаление ссылок на представление из клонированного листа. </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> CleanView(<SPAN style="COLOR: #2b91af">WorksheetPart</SPAN> worksheetPart) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//There can only be one sheet that has focus </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SheetViews</SPAN> views = worksheetPart.Worksheet.GetFirstChild&lt;<SPAN style="COLOR: #2b91af">SheetViews</SPAN>&gt;(); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">if</SPAN> (views != <SPAN style="COLOR: blue">null</SPAN>) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">views.Remove(); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">worksheetPart.Worksheet.Save(); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Исправление разделов таблиц предполагает проверку наличия у каждой таблицы уникального имени и идентификатора. </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> FixupTableParts(<SPAN style="COLOR: #2b91af">WorksheetPart</SPAN> worksheetPart, <SPAN style="COLOR: blue">int</SPAN> numTableDefParts) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Every table needs a unique id and name </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: #2b91af">TableDefinitionPart</SPAN> tableDefPart <SPAN style="COLOR: blue">in</SPAN> worksheetPart.TableDefinitionParts) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableId++; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableDefPart.Table.Id = (<SPAN style="COLOR: blue">uint</SPAN>)tableId; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableDefPart.Table.DisplayName = <SPAN style="COLOR: #a31515">"CopiedTable"</SPAN> + tableId; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableDefPart.Table.Name = <SPAN style="COLOR: #a31515">"CopiedTable"</SPAN> + tableId; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">tableDefPart.Table.Save(); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Все в порядке. Последний шаг — это добавление ссылки на добавленный лист в основной раздел книги с помощью следующего кода: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> CopySheet(<SPAN style="COLOR: blue">string</SPAN> filename, <SPAN style="COLOR: blue">string</SPAN> sheetName, <SPAN style="COLOR: blue">string</SPAN> clonedSheetName) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Add new sheet to main workbook part </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">Sheets</SPAN> sheets = workbookPart.Workbook.GetFirstChild&lt;<SPAN style="COLOR: #2b91af">Sheets</SPAN>&gt;(); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">Sheet</SPAN> copiedSheet = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">Sheet</SPAN>(); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">copiedSheet.Name = clonedSheetName; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">copiedSheet.Id = workbookPart.GetIdOfPart(clonedSheet); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">copiedSheet.SheetId = (<SPAN style="COLOR: blue">uint</SPAN>)sheets.ChildElements.Count + 1; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">sheets.Append(copiedSheet); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Save Changes </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">workbookPart.Workbook.Save(); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><H2>Заключение </H2><P>Объединив все фрагменты и выполнив предложенный код, мы получим книгу с четырьмя листами, где последний лист, названный "CopiedData", является точной копией первого листа. </P><P>Вот снимок экрана с созданной книгой: </P><P><IMG alt="Снимок экрана с книгой Excel после выполнения кода" src="https://zeyadrajabi.members.winisp.net/screen2.png"> </P><P>Зияд Раджаби (Zeyad Rajabi)</P><img src="https://blogs.msdn.com/aggbug.aspx?PostID=9434684" width="1" height="1"><p>Это локализованная запись блога. Исходную статью можно найти по адресу <a href='https://blogs.msdn.com/brian_jones/archive/2009/02/19/how-to-copy-a-worksheet-within-a-workbook.aspx'>https://blogs.msdn.com/brian_jones/archive/2009/02/19/how-to-copy-a-worksheet-within-a-workbook.aspx</a>.]]></content:encoded>
    </item>
    <item>
      <title>Пакет Open XML SDK: основные сведения</title>
      <link>https://docs.microsoft.com/archive/blogs/brian_jones_ru/open-xml-sdk</link>
      <pubDate>Thu, 02 Jul 2009 17:37:19 GMT</pubDate>
      <dc:creator><![CDATA[OfficeLocalization]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brian_jones_ru/2009/07/02/open-xml-sdk/</guid>
      <description><![CDATA[Привет! Меня зовут Али. Я являюсь разработчиком в команде разработчиков Word. Я также работал над...]]></description>
      <content:encoded><![CDATA[<P style="MARGIN-LEFT: 36pt"><EM>Привет! Меня зовут Али. Я являюсь разработчиком в команде разработчиков Word. Я также работал над функциональностью пакета Open XML SDK и в этой публикации хочу подробнее рассказать о пакете SDK и лежащей в его основе концепции. </EM></P><P>В своих записях <A href="https://blogs.msdn.com/brian_jones/archive/tags/Zeyad_2700_s+SDK+Examples/default.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/tags/Zeyad_2700_s+SDK+Examples/default.aspx">Зияд Раджаби (Zeyad Rajabi)</A> и <A href="https://blogs.msdn.com/ericwhite/" mce_href="https://blogs.msdn.com/ericwhite/">Эрик Уайт (Eric White)</A> продемонстрировали множество отличных решений (например, <A href="https://blogs.msdn.com/brian_jones/archive/2009/01/05/taking-advantage-of-bound-content-controls.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/01/05/taking-advantage-of-bound-content-controls.aspx">"Использование преимущества связанных элементов управления содержимым"</A> и <A href="https://blogs.msdn.com/ericwhite/archive/2009/01/10/accepting-revisions-removing-comments-and-removing-personal-info-from-a-sharepoint-document-library-using-web-services.aspx" mce_href="https://blogs.msdn.com/ericwhite/archive/2009/01/10/accepting-revisions-removing-comments-and-removing-personal-info-from-a-sharepoint-document-library-using-web-services.aspx">"Принятие исправлений и удаление примечаний из документа SharePoint"</A>), которые можно построить с помощью пакета Open XML SDK для создания, чтения или изменения документов, электронных таблиц и презентаций. В каждой записи присутствовал сценарий и был продемонстрирован код для его реализации. Здесь я хочу более подробно обсудить содержимое пакета SDK и то, чем обусловлены некоторые из представленных в нем подходов. У меня нет сценария, есть лишь некоторые заметки, дающие представление о том, из чего состоит пакет SDK и почему. </P><P>Я работаю над Word, поэтому все мои примеры будут касаться компонентов WordProcessingML, хотя все представленное применимо и к другим форматам. </P><H2>Это всего лишь XML! </H2><P>Помимо пакетов и разделов пакет SDK включает иерархию типов, таких как Paragraph. Для успешного использования SDK важно знать, что эти классы всего лишь представляют элементы XML и действуют так же, но с несколько большей интеграцией с типами. </P><P>В корне иерархии располагается (абстрактный) класс OpenXMLElement. Класс OpenXMLElement программно представляет любой старый элемент, фигурирующий в файле Open XML. Имя его довольно ясно представляет элемент XML. Предоставленные методы и свойства также соответствуют ожиданиям в отношении элементов XML: .FirstChild, .InnerText, .NextSibling(), Append(OpenXMLElement) и т.д. </P><P>Класс OpenXMLElement сам по себе предоставляет некоторые функции (как все хорошие базовые классы), которые мы рассмотрим ниже, но производные от него классы представляют больший интерес. Для каждого элемента, указанного в спецификации Open XML, существует соответствующий класс в SDK, производный (опосредовано) от класса OpenXMLElement. Во-первых, существует еще два абстрактных класса, предназначенных для того, чтобы отличать элементы, которые могут иметь другие элементы в качестве дочерних и те, которые не могут, — это классы OpenXMLCompositeElement и OpenXMLLeafElement. </P><P>Класс Paragraph, например, является производным от класса OpenXMLCompositeElement. "Ну и что?" — спросите вы. Хорошо, начнем с простого. Если вам приходилось писать код, управляющий объектами XmlElement, вы знаете, как трудно постоянно сверять имя и пространство имен, чтобы определить, с каким элементом вы в данный момент работаете. Благодаря иерархии типов, представляющей элементы, вы всегда получаете наиболее производный тип для элемента из методов Open XML SDK, возвращающих объекты OpenXMLElement. Например, свойство Body.FirstChild возвращает экземпляр класса Paragraph, если первый дочерний элемент элемента w:body в считываемом документе действительно является элементом w:p. В противном случае возвращается какой-либо другой тип. Так, вместо проверки имени и пространства имен элемента можно проверить его тип, например: </P><DIV style="MARGIN-LEFT: 36pt"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">Paragraph</SPAN> p = child <SPAN style="COLOR: blue">as</SPAN> <SPAN style="COLOR: #2b91af">Paragraph</SPAN>; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">if</SPAN> (p != <SPAN style="COLOR: blue">null</SPAN>) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 25pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: green">// Do something ... </SPAN></SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN> </DIV></DIV><P>Я хочу лишний раз подтвердить, что тут нет никакой магии. Пакет SDK действительно проверил имя и пространство имен для выбора класса Paragraph подобно тому, как сделал бы ваш код. Дополнительное преимущество заключается в том, что вам не надо каждый раз писать эти проверки самостоятельно. Конечно, наличие типа имеет и другие преимущества. Для начала можно написать функции, принимающие аргумент типа Paragraph, а компилятор будет следить за выполнением этого контракта вместо вас. </P><P>Более того, когда элементы различаются по типу, можно использовать универсальные типы для обеспечения большей чистоты кода. Помните, что я упоминал о том, что OpenXMLElement сам по себе обладает некоторыми полезными функциями? Взгляните на метод GetFirstChild&lt;T&gt;, где T является производным от OpenXMLElement. Как можно представить, этот метод возвращает первый дочерний элемент, принадлежащий определенному типу. Снова все, что делает SDK, это проверяет имя и пространство имен вместо вас, но полученная очистка кода существенна. Descendants&lt;T&gt;(), RemoveAllChildren&lt;T&gt;(), ReplaceChild&lt;T&gt;(), Ancestors&lt;T&gt;() и прочие методы действуют подобным образом. </P><P>Еще одним преимуществом наличия этих типов является возможность использования ключевого слова "new". Хотите создать элемент w:b (полужирный)? Просто сделайте это: </P><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">Bold</SPAN> b = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">Bold</SPAN>(); </SPAN></DIV><P>Помните, что это просто особый способ работы с XML. Что я сделал? Я создал элемент XML в пространстве имен WordProcessingML (конечно, в зависимости от того, в какой оператор using разрешается тип Bold) с именем "b". Этот элемент еще не принадлежит какому-либо документу, его необходимо добавить (с помощью метода InsertAfter, AppendChild и т.д.). </P><P>Наличие спецификации Open XML позволило пакету SDK представлять отдельные элементы как собственные типы и добавлять функции, упрощающие обработку элементов благодаря их типам. </P><H2>Свойства первого класса </H2><P>До этого момента мы использовали схему только как список имен и пространств имен элементов, хотя этот список и был очень большим. Схема сообщает нам гораздо больше, в частности, какие элементы и атрибуты допустимы в качестве дочерних для того или иного элемента. Например, элемент w:sdt (тег структуры документа уровня последовательности знаков) в WordProcessingML может иметь максимум один дочерний элемент типа w:sdtPr (свойства SDT). Учитывая изложенное выше, мы можем использовать универсальный метод GetFirstChild&lt;T&gt;() для поиска этого элемента свойств следующим образом: </P><DIV style="MARGIN-LEFT: 36pt"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SdtProperties</SPAN> sdtPr = sdtRun.GetFirstChild&lt;<SPAN style="COLOR: #2b91af">SdtProperties</SPAN>&gt;(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">if</SPAN> (sdtPr != <SPAN style="COLOR: blue">null</SPAN>) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 25pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: green">// Do something ... </SPAN></SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN> </DIV></DIV><P>Следует заметить, что нам не надо приводить возвращаемое значение GetFirstChild. Это лучше, чем циклический перебор всех дочерних элементов с проверкой имен и пространств имен с целью поиска элемента sdtPr, но по-прежнему не самый простой способ, поскольку он требует повтора действий на каждом уровне. Класс SdtRun в SDK имеет свойство SdtProperties, представляющее этот дочерний элемент. Таким образом, фрагмент кода будет иметь следующий вид: </P><DIV style="MARGIN-LEFT: 36pt"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SdtProperties</SPAN> sdtPr = sdtRun.SdtProperties; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">if</SPAN> (sdtPr != <SPAN style="COLOR: blue">null</SPAN>) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 25pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: green">// Do something ... </SPAN></SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV></DIV><P>Это свойство доступно для чтения и записи. Теперь возьмем объект RunProperties. </P><DIV style="MARGIN-LEFT: 36pt"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">RunProperties</SPAN> rPr = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">RunProperties</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.Italic = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">Italic</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.Bold = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">Bold</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.NoProof = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">NoProof</SPAN>();</SPAN> </DIV></DIV><P>Что произошло? Мы создали элемент w:rPr и присвоили его свойство Bold новому экземпляру класса Bold. При этом был создан элемент w:b, который при присвоении был присоединен в качестве дочернего к нашему элементу rPr. То же происходит и со свойствами Italic и NoProof. Снова никакой магии тут нет, это всего лишь сокращенные варианты операций, выполняемых как операции с исходным кодом XML, позволяющие значительно сократить и упростить код. </P><P>В этих четырех строках скрыта еще более ценная функция. Ниже представлен аналогичный код, но без использования свойств первого класса. Что тут не так? </P><DIV style="MARGIN-LEFT: 36pt"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">RunProperties</SPAN> rPr = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">RunProperties</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.AppendChild(<SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">Italic</SPAN>()); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.AppendChild(<SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">Bold</SPAN>()); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.AppendChild(<SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">NoProof</SPAN>()); </SPAN></DIV></DIV><P>Этот фрагмент кода создает документ с недопустимой схемой. В схеме указаны дочерние элементы элемента rPr как последовательность, поэтому порядок имеет значение. Согласно схеме, чтобы файл был допустимым, Bold (w:b) должен следовать перед Italics (w:i). Фрагмент кода, в котором использовано присвоение свойств, выполняет эту задачу правильно (поскольку фоновый код присвоений "знает" о порядке, которому должен подчиняться второй код). </P><P>Теперь подведем итог того, что мы увидели в примерах. Если схема разрешает использование только одного экземпляра дочернего элемента, в класс, представляющий родительский элемент, добавляется свойство этого типа и с тем же именем. Значение свойства может быть доступно для чтения или записи, а присвоение свойству добавляет (или переопределяет) дочерний элемент по отношению к родительскому. </P><P>А как же атрибуты? Атрибуты по определению отвечают приведенным выше критериям (каждый атрибут в каждом элементе может фигурировать не более одного раза). Так, атрибуты, объявленные в схеме, всегда получают свойства первого класса. Например, к приведенным выше свойствам выполнения мы можем добавить Underline. </P><DIV style="MARGIN-LEFT: 36pt"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">RunProperties</SPAN> rPr = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">RunProperties</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.Italic = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">Italic</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.Bold = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">Bold</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.Underline = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">Underline</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.Underline.Val = <SPAN style="COLOR: #2b91af">UnderlineValues</SPAN>.DotDotDash;</SPAN> </DIV></DIV><P>Последняя строка представляет наибольший интерес. Во-первых, обратите внимание на свойство Val в элементе Underline. Оно представляет атрибут w:val этого элемента. Как обычно, выполняя присвоение этому свойству, мы создаем экземпляр атрибута и помещаем его в элемент. Значения атрибута, конечно, строковые, но, если схема указывает, что они являются членами перечисления, SDK также содержит соответствующее перечисление CLR. Имя перечисления создается таким, чтобы оно было узнаваемо: например, <EM>Type</EM>Values. Здесь можно долго говорить о специфике и "удобстве" синтаксиса присвоения, предполагающего неявные конструкторы и прочее, но я оставлю это для самостоятельного изучения читателями. Укажу лишь на то, что атрибут Val здесь жестко типизирован. Следующий оператор скомпилирован не будет: </P><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.Underline.Val = <SPAN style="COLOR: #2b91af">BooleanValues</SPAN>.False;</SPAN> </DIV><H2>Это всего лишь XML! Правда! </H2><P>Ладно, вернемся к началу. Я надеюсь, что мне удалось продемонстрировать, как SDK добавляет значение, используя компактные и простые способы, позволяющие создавать более понятный и чистый код для создания, чтения файлов Open XML и работы с ними. В заключение упомяну еще некоторые моменты. </P><UL><LI>Не позволяйте свойствам вводить вас в заблуждение, считая, что объекты всегда присутствуют. В действительности вы оперируете элементами и атрибутами XML и порой они просто отсутствуют. <SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.Underline</SPAN> может вернуть значение NULL, например, если w:rPr не имеет дочернего элемента Underline. Даже если значение не NULL, <SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">rPr.Underline.Val</SPAN> может вернуть значение NULL, если элемент присутствует, но отсутствует атрибут Val. </LI><LI>Создавать элементы с помощью ключевого слова "new" очень просто и интересно, но даже такой способ может оказаться трудоемким из-за большого размера иерархии элементов, в частности, когда создаваемые элементы подобны. Например, представьте, что вашему приложению требуется добавить таблицу в документ. Кроме того, первые три строки таблицы всегда одинаковы (скажем, заголовок). Вместо создания объекта Table, трех объектов Row и множества объектов Cell для каждого из объектов Row с последующим добавлением ячеек в строки, а строк — в таблицу, можно просто воспользоваться конструкцией, предоставленной классом Table, которая использует в качестве входящего значения строку XML. Конечно, предоставляемый XML должен иметь надлежащий формат (т.е. необходимо будет закрыть теги w:tbl и т.д.), но затем можно будет добавить в полученный объект Table дополнительные строки. </LI><LI>LINQ. В большинстве примеров, приведенных Зиядом и Эриком, используется исключительно LINQ. Хотя Open XML SDK разрабатывался для работы с LINQ, явного требования использовать LINQ здесь нет. Как правило, при создании элементов XML (таких, как приведенные выше примеры с элементом rPr) простой императивный код оказывается более удобочитаемым, чем аналоги LINQ. Точно так же запросы LINQ (лишний раз повторюсь) оказываются короче, когда необходимо задать такой простой вопрос, как "содержит ли этот документ какие-либо теги SDT с данным значением псевдонима?". </LI></UL><P>-Али</P><img src="https://blogs.msdn.com/aggbug.aspx?PostID=9312073" width="1" height="1"><p>Это локализованная запись блога. Исходную статью можно найти по адресу <a href='https://blogs.msdn.com/brian_jones/archive/2009/01/12/open-xml-sdk-the-basics.aspx'>https://blogs.msdn.com/brian_jones/archive/2009/01/12/open-xml-sdk-the-basics.aspx</a>.]]></content:encoded>
    </item>
    <item>
      <title>Удаление примечаний из файлов Excel и PowerPoint</title>
      <link>https://docs.microsoft.com/archive/blogs/brian_jones_ru/excel</link>
      <pubDate>Thu, 02 Jul 2009 17:37:15 GMT</pubDate>
      <dc:creator><![CDATA[OfficeLocalization]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brian_jones_ru/2009/07/02/excel/</guid>
      <description><![CDATA[В предыдущей записи я показал, как удалять примечания из файла Word. Сегодня я продемонстрирую, как...]]></description>
      <content:encoded><![CDATA[<P>В предыдущей записи я показал, <A href="https://blogs.msdn.com/brian_jones/archive/2009/02/06/removing-comments-from-a-wordprocessing-document-programmatically.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/02/06/removing-comments-from-a-wordprocessing-document-programmatically.aspx">как удалять примечания из файла Word</A>. Сегодня я продемонстрирую, как выполняется этот же сценарий, но с файлами Excel и PowerPoint. В Excel и PowerPoint есть функция "Инспектор документов", которая позволяет удалять различные типы данных и содержимого, включая примечания. Эта функция очень хорошо работает в клиентских решениях, но как выполнить очистку файлов от примечаний на сервере? Open XML SDK может справиться с этой задачей с помощью всего нескольких строк кода. </P><P><EM>Примечание. Представленный здесь код обратно совместим с <A href="https://go.microsoft.com/fwlink/?LinkId=120908" mce_href="https://go.microsoft.com/fwlink/?LinkId=120908">версией 1 пакета SDK</A>.</EM></P><H2>Решение для PowerPoint </H2><P>Допустим, я начинаю работу с презентацией PowerPoint, содержащей множество слайдов и примечаний. Вот снимок экрана, на котором изображены примечания внутри слайда PowerPoint: </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/042009_2242_RemovingCom1.png" mce_src="https://zeyadrajabi.members.winisp.net/042009_2242_RemovingCom1.png"> </P><P>Для удаления примечаний из презентации PowerPoint необходимо выполнить следующие действия: </P><OL><LI>Открыть презентацию PowerPoint с помощью пакета Open XML SDK. </LI><LI>Получить доступ к главному разделу презентации, который предоставляет доступ ко всем разделам слайдов в пакете. </LI><LI>Удалить раздел примечаний, связанный с каждым разделом слайда. </LI><LI>Сохранить изменения презентации. </LI></OL><P>Если вы хотите отслеживать все этапы работы непосредственно по коду, наше решение можно без труда загрузить <A href="https://zeyadrajabi.members.winisp.net/sourcecode/RemovePowerPointComments.zip" mce_href="https://zeyadrajabi.members.winisp.net/sourcecode/RemovePowerPointComments.zip">здесь</A>. </P><H3>Код </H3><P>Код довольно простой и полностью соответствует перечисленным выше шагам. </P><DIV><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 638px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; PADDING-BOTTOM: 1px; BORDER-LEFT: black 0.5pt solid; PADDING-TOP: 1px; BORDER-BOTTOM: black 0.5pt solid" vAlign=center><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> RemovePowerPointComments(<SPAN style="COLOR: blue">string</SPAN> filename) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">using</SPAN> (<SPAN style="COLOR: #2b91af">PresentationDocument</SPAN> myPresentation = <SPAN style="COLOR: #2b91af">PresentationDocument</SPAN>.Open(filename, <SPAN style="COLOR: blue">true</SPAN>)) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">PresentationPart</SPAN> presentationPart = myPresentation.PresentationPart; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: #2b91af">SlidePart</SPAN> slide <SPAN style="COLOR: blue">in</SPAN> presentationPart.SlideParts) </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">slide.DeletePart(slide.SlideCommentsPart); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><H3>Заключение </H3><P>Выполнив этот метод, мы получим презентацию без примечаний. Легко! </P><P>Вот снимок экрана с итоговой презентацией: </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/042009_2242_RemovingCom2.png" mce_src="https://zeyadrajabi.members.winisp.net/042009_2242_RemovingCom2.png"> </P><H2>Решение для Excel </H2><P>Это решение очень похоже на решение для PowerPoint. </P><P>Допустим, у нас есть книга Excel с множеством листов, каждый из которых содержит несколько примечаний. Вот снимок экрана, на котором изображено примечание в ячейке листа: </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/042009_2242_RemovingCom3.png" mce_src="https://zeyadrajabi.members.winisp.net/042009_2242_RemovingCom3.png"> </P><P>Для удаления примечаний из книги Excel необходимо выполнить следующие действия: </P><OL><LI>Открыть книгу Excel с помощью пакета Open XML SDK. </LI><LI>Получить доступ к главному разделу книги, который предоставляет доступ ко всем разделам листов в пакете. </LI><LI>Удалить все примечания, связанные с каждым разделом листа. </LI><LI>Сохранить изменения в книге. </LI></OL><P>Если вы хотите отслеживать все этапы работы непосредственно по коду, наше решение можно без труда загрузить <A href="https://zeyadrajabi.members.winisp.net/sourcecode/RemoveExcelComments.zip" mce_href="https://zeyadrajabi.members.winisp.net/sourcecode/RemoveExcelComments.zip">здесь</A>. </P><H3>Код </H3><P>Код очень похож на код, используемый для удаления примечаний из презентации PowerPoint. </P><DIV><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 638px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; PADDING-BOTTOM: 1px; BORDER-LEFT: black 0.5pt solid; PADDING-TOP: 1px; BORDER-BOTTOM: black 0.5pt solid" vAlign=center><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> RemoveExcelComments(<SPAN style="COLOR: blue">string</SPAN> filename) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">using</SPAN> (<SPAN style="COLOR: #2b91af">SpreadsheetDocument</SPAN> myWorkbook = <SPAN style="COLOR: #2b91af">SpreadsheetDocument</SPAN>.Open(filename, <SPAN style="COLOR: blue">true</SPAN>)) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">WorkbookPart</SPAN> workbookPart = myWorkbook.WorkbookPart; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: #2b91af">WorksheetPart</SPAN> sheet <SPAN style="COLOR: blue">in</SPAN> workbookPart.WorksheetParts) </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">sheet.DeleteParts&lt;<SPAN style="COLOR: #2b91af">WorksheetCommentsPart</SPAN>&gt;(sheet.GetPartsOfType&lt;<SPAN style="COLOR: #2b91af">WorksheetCommentsPart</SPAN>&gt;()); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><H3>Заключение </H3><P>Выполнив этот метод, мы получим книгу без примечаний. </P><P>Вот снимок экрана с итоговой книгой: </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/042009_2242_RemovingCom4.png" mce_src="https://zeyadrajabi.members.winisp.net/042009_2242_RemovingCom4.png"> </P><P>Зияд Раджаби (Zeyad Rajabi)</P><img src="https://blogs.msdn.com/aggbug.aspx?PostID=9557592" width="1" height="1"><p>Это локализованная запись блога. Исходную статью можно найти по адресу <a href='https://blogs.msdn.com/brian_jones/archive/2009/04/20/removing-comments-from-excel-and-powerpoint-files.aspx'>https://blogs.msdn.com/brian_jones/archive/2009/04/20/removing-comments-from-excel-and-powerpoint-files.aspx</a>.]]></content:encoded>
    </item>
    <item>
      <title>Импорт диаграмм из электронных таблиц в текстовые документы</title>
      <link>https://docs.microsoft.com/archive/blogs/brian_jones_ru/93</link>
      <pubDate>Thu, 02 Jul 2009 17:37:13 GMT</pubDate>
      <dc:creator><![CDATA[OfficeLocalization]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brian_jones_ru/2009/07/02/93/</guid>
      <description><![CDATA[Многие читатели спрашивают, как можно импортировать диаграмму из документа одного типа в документ...]]></description>
      <content:encoded><![CDATA[<P>Многие читатели спрашивают, как можно импортировать диаграмму из документа одного типа в документ другого типа. В своей прошлой записи блога я показал, <A href="https://blogs.msdn.com/brian_jones/archive/2008/11/04/document-assembly-solution-for-spreadsheetml.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2008/11/04/document-assembly-solution-for-spreadsheetml.aspx">как поместить данные в таблицу для создания диаграммы</A>. Сегодня я продемонстрирую процедуру импорта диаграммы из электронной таблицы в документ Word. </P><H2>Решение </H2><P>Для импорта диаграммы из электронной таблицы в документ Word потребуется выполнить следующие действия: </P><OL><LI>Создать в программе Word шаблон, содержащий элемент управления содержимым, который будет определять область для вставки диаграммы. </LI><LI>Открыть созданный документ Word с помощью пакета Open XML SDK и получить доступ к главному разделу документа. </LI><LI>Найти элемент управления содержимым, в котором планируется разместить диаграмму. </LI><LI>Удалить все замещающее содержимое в этом элементе управления. </LI><LI>Создать новый экземпляр класса Run и встроенный объект-рисунок для вставки в данный элемент управления содержимым. Этот встроенный объект-рисунок будет содержать ссылочные сведения для диаграммы. </LI><LI>Открыть электронную таблицу с помощью пакета Open XML SDK и получить доступ к соответствующим разделам (к главному разделу книги, разделам электронной таблицы, рисунка и диаграммы). </LI><LI>Скопировать раздел диаграммы и добавить его в документ Word. </LI><LI>Скопировать графические сведения о диаграмме (имя диаграммы и ее свойства) из электронной таблицы и добавить их в документ Word. </LI><LI>Присвоить диаграмме в документе Word уникальные имя и идентификатор. </LI><LI>Добавить данные диаграммы в элемент управления содержимым. </LI><LI>Сохранить изменения документа Word. </LI></OL><P>В моей демонстрации будет использоваться <A href="https://go.microsoft.com/fwlink/?LinkId=127912" mce_href="https://go.microsoft.com/fwlink/?LinkId=127912">пакет SDK версии 2</A>. </P><P>Чтобы более наглядно представить изложенный здесь материал, начнем работать со следующей электронной таблицей и диаграммой: </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/031309_1725_ImportingCh1.png" mce_src="https://zeyadrajabi.members.winisp.net/031309_1725_ImportingCh1.png"> </P><P>Кроме того, мы будем использовать следующий документ Word, содержащий замещающий элемент управления содержимым: </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/031309_1725_ImportingCh2.png" mce_src="https://zeyadrajabi.members.winisp.net/031309_1725_ImportingCh2.png"> </P><P>Если вы хотите отслеживать все этапы работы непосредственно по коду, наше решение можно без труда загрузить <A href="https://zeyadrajabi.members.winisp.net/sourcecode/ImportChartFromExcelToWord.zip" mce_href="https://zeyadrajabi.members.winisp.net/sourcecode/ImportChartFromExcelToWord.zip">здесь</A>. </P><H2>Код </H2><P>Как уже указывалось в разделе "Решение" выше, шаги 2–4 включают открытие документа Word, поиск элемента управления содержимым, в котором будет помещена импортированная диаграмма, и удаление замещающего содержимого этого элемента управления для подготовки к вставке диаграммы. Взгляните на фрагмент кода, в котором реализуется выполнение этих задач: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> ImportChartFromSpreadsheet(<SPAN style="COLOR: blue">string</SPAN> spreadsheetFileName, <SPAN style="COLOR: blue">string</SPAN> wordFileName) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Open Word document </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">using</SPAN> (<SPAN style="COLOR: #2b91af">WordprocessingDocument</SPAN> myWordDoc = <SPAN style="COLOR: #2b91af">WordprocessingDocument</SPAN>.Open(wordFileName, <SPAN style="COLOR: blue">true</SPAN>)) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Find the content control that will contain the chart </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">MainDocumentPart</SPAN> mainPart = myWordDoc.MainDocumentPart; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SdtBlock</SPAN> sdt = mainPart.Document.Descendants&lt;<SPAN style="COLOR: #2b91af">SdtBlock</SPAN>&gt;() </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.Where(s =&gt; a.SdtProperties.GetFirstChild&lt;<SPAN style="COLOR: #2b91af">Alias</SPAN>&gt;().Val.Value </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.Equals(<SPAN style="COLOR: #a31515">"Chart1"</SPAN>)).First(); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Nuke the placeholder content of the content control </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">Paragraph</SPAN> p = sdt.SdtContentBlock.GetFirstChild&lt;<SPAN style="COLOR: #2b91af">Paragraph</SPAN>&gt;(); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">p.RemoveAllChildren(); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Вы, наверно, заметили, что код, используемый для поиска соответствующего элемента управления содержимым, очень напоминает код, продемонстрированный в моей предыдущей записи для <A href="https://blogs.msdn.com/brian_jones/archive/2008/12/08/the-easy-way-to-assemble-multiple-word-documents.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2008/12/08/the-easy-way-to-assemble-multiple-word-documents.aspx">объединения документов Word</A>. Чтобы подготовить элемент управления к вставке диаграммы, внутри него удаляются все дочерние элементы класса Paragraph. </P><P>Вместо работы с экземпляром класса Run и текстовыми элементами для данного элемента управления содержимым требуется создать экземпляр класса Run и встроенный объект-рисунок, необходимый для создания правильной ссылки на диаграмму. Эта задача выполняется с помощью следующего фрагмента кода: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Create a new run that has an inline drawing object </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">Run</SPAN> r = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">Run</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">p.Append(r); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">Drawing</SPAN> drawing = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">Drawing</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">r.Append(drawing); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//These dimensions work perfectly for my template document </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">wp.<SPAN style="COLOR: #2b91af">Inline</SPAN> inline = <SPAN style="COLOR: blue">new</SPAN> wp.<SPAN style="COLOR: #2b91af">Inline</SPAN>( </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">new</SPAN> wp.<SPAN style="COLOR: #2b91af">Extent</SPAN>() </SPAN></DIV><DIV style="MARGIN-LEFT: 180pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ Cx = 5486400, Cy = 3200400 }); </SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Обратите внимание, что размеры импортируемой диаграммы в моем коде жестко заданы. Я ввел те размеры, которые, как мне кажется, лучше всего подходят к шаблону. Вы можете использовать любые размеры, соответствующие вашему документу. На данном этапе документ Word полностью готов для импорта диаграммы и ее вставки в элемент управления содержимым. Для импорта диаграммы необходимо получить доступ к соответствующему разделу диаграммы, а затем добавить этот раздел в документ Word. Эти задачи реализованы в следующем фрагменте кода: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class=style1 style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid" class="style1"><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Open Excel spreadsheet </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">using</SPAN> (<SPAN style="COLOR: #2b91af">SpreadsheetDocument</SPAN> mySpreadsheet = </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SpreadsheetDocument</SPAN>.Open(spreadsheetFileName, <SPAN style="COLOR: blue">true</SPAN>)) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Get all the appropriate parts </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">WorkbookPart</SPAN> workbookPart = mySpreadsheet.WorkbookPart; </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">WorksheetPart</SPAN> worksheetPart = (<SPAN style="COLOR: #2b91af">WorksheetPart</SPAN>)workbookPart.GetPartById(<SPAN style="COLOR: #a31515">"rId1"</SPAN>); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">DrawingsPart</SPAN> drawingPart = worksheetPart.DrawingsPart; </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">ChartPart</SPAN> chartPart = (<SPAN style="COLOR: #2b91af">ChartPart</SPAN>)drawingPart.GetPartById(<SPAN style="COLOR: #a31515">"rId1"</SPAN>); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Clone the chart part and add it to my Word document </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">ChartPart</SPAN> importedChartPart = mainPart.AddPart&lt;<SPAN style="COLOR: #2b91af">ChartPart</SPAN>&gt;(chartPart); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">string</SPAN> relId = mainPart.GetIdOfPart(importedChartPart); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">...<SPAN style="COLOR: green"> </SPAN></SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Раздел диаграммы теперь входит в состав пакета документа Word. Нам осталось только правильно создать ссылку на этот раздел из встроенного объекта-рисунка, который находится внутри элемента управления содержимым. Чтобы наш код заработал, потребуется выполнить две задачи. </P><OL><LI>Создать графическую ссылку на раздел диаграммы. </LI><LI>Присвоить каждой диаграмме уникальные идентификатор и имя. </LI></OL><P>Выполнение первой задачи не составляет никакого труда, поскольку можно повторно использовать те же графические объекты из электронной таблицы. Однако потребуется убедиться, что отношение ссылается на соответствующий раздел диаграммы в документе Word (именно в этом и состоит главное отличие). Вот фрагмент кода, в котором реализуется первая задача: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//The frame element contains information for the chart </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">GraphicFrame</SPAN> frame = </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">drawingPart.WorksheetDrawing.Descendants&lt;<SPAN style="COLOR: #2b91af">GraphicFrame</SPAN>&gt;().First(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">string</SPAN> chartName = frame.NonVisualGraphicFrameProperties.NonVisualDrawingProperties.Name; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Clone this node so we can add it to my Word document </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">d.<SPAN style="COLOR: #2b91af">Graphic</SPAN> clonedGraphic = (d.<SPAN style="COLOR: #2b91af">Graphic</SPAN>)frame.Graphic.CloneNode(<SPAN style="COLOR: blue">true</SPAN>); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">ChartReference</SPAN> c = clonedGraphic.GraphicData.GetFirstChild&lt;<SPAN style="COLOR: #2b91af">ChartReference</SPAN>&gt;(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">c.Id = relId;</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P><BR>Для выполнения второй задачи требуется вычислить уникальный идентификатор для диаграммы. Это можно сделать, например, с помощью следующего метода: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">uint</SPAN> GetMaxDocPrId(<SPAN style="COLOR: #2b91af">MainDocumentPart</SPAN> mainPart) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">uint</SPAN> max = 1; </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Get max id value of docPr elements </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (wp.<SPAN style="COLOR: #2b91af">DocProperties</SPAN> docPr <SPAN style="COLOR: blue">in</SPAN> mainPart.Document.Descendants&lt;wp.<SPAN style="COLOR: #2b91af">DocProperties</SPAN>&gt;()) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">uint</SPAN> id = docPr.Id; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">if</SPAN> (id &gt; max) </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">max = id; </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">return</SPAN> max; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Мы почти закончили! Теперь остается только присвоить уникальные имя и идентификатор рисунку диаграммы и добавить все это во встроенный объект-рисунок. Эти задачи выполнены в следующем фрагменте кода: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Give the chart a unique id and name </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">wp.<SPAN style="COLOR: #2b91af">DocProperties</SPAN> docPr = <SPAN style="COLOR: blue">new</SPAN> wp.<SPAN style="COLOR: #2b91af">DocProperties</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">docPr.Name = chartName; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">docPr.Id = GetMaxDocPrId(mainPart) + 1; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//add the chart data to the inline drawing object </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">inline.Append(docPr, clonedGraphic); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">drawing.Append(inline);</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><H2>Заключение </H2><P>Собрав вместе все показанные фрагменты и запустив итоговый код, мы получим документ Word, который содержит диаграмму, импортированную из электронной таблицы. </P><P>Взгляните на снимок экрана, на котором показан окончательный документ: </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/031309_1725_ImportingCh3.png" mce_src="https://zeyadrajabi.members.winisp.net/031309_1725_ImportingCh3.png"> </P><P>Зияд Раджаби (Zeyad Rajabi)</P><img src="https://blogs.msdn.com/aggbug.aspx?PostID=9473422" width="1" height="1"><p>Это локализованная запись блога. Исходную статью можно найти по адресу <a href='https://blogs.msdn.com/brian_jones/archive/2009/03/13/importing-charts-from-spreadsheets-to-wordprocessing-documents.aspx'>https://blogs.msdn.com/brian_jones/archive/2009/03/13/importing-charts-from-spreadsheets-to-wordprocessing-documents.aspx</a>.]]></content:encoded>
    </item>
    <item>
      <title>Удаление примечаний из текстового документа программными средствами</title>
      <link>https://docs.microsoft.com/archive/blogs/brian_jones_ru/103</link>
      <pubDate>Thu, 02 Jul 2009 17:37:03 GMT</pubDate>
      <dc:creator><![CDATA[OfficeLocalization]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brian_jones_ru/2009/07/02/103/</guid>
      <description><![CDATA[Один из наиболее распространенных сценариев, связанных с текстовыми документами, заключается в...]]></description>
      <content:encoded><![CDATA[<P>Один из наиболее распространенных сценариев, связанных с текстовыми документами, заключается в очистке документа с целью удаления любых содержащихся в нем личных сведений. Что я подразумеваю под личными сведениями? В первую очередь, я имею в виду примечания, редакции, персональные данные, такие как имя автора и скрытый текст. Этот тип содержимого часто требуется вычистить из документа, прежде чем он будет опубликован за пределами компании. </P><P>Этот сценарий настолько важен для программ Office, что в пакете Office 2007 мы добавили новый компонент под названием "Document Inspector", который способен находить и удалять любые личные сведения. Чтобы открыть этот компонент, необходимо нажать кнопку Office и последовательно выбрать "Prepare", "Inspect Document". Вот как выглядит окно инспектора документов: </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/020609_1959_RemovingCom1.png" mce_src="https://zeyadrajabi.members.winisp.net/020609_1959_RemovingCom1.png"> </P><P>А как выполнить те же действия программными средствами, скажем, на сервере? Здесь как раз нам может помочь пакет Open XML SDK. Сегодня я собираюсь продемонстрировать процедуру удаления примечаний из текстового документа. Данная запись аналогична записи Эрика по поводу использования <A href="https://blogs.msdn.com/ericwhite/archive/2008/07/14/using-the-open-xml-sdk-and-linq-to-xml-to-remove-comments-from-an-open-xml-wordprocessing-document.aspx" mce_href="https://blogs.msdn.com/ericwhite/archive/2008/07/14/using-the-open-xml-sdk-and-linq-to-xml-to-remove-comments-from-an-open-xml-wordprocessing-document.aspx">LINQ для удаления примечаний из документа</A> с тем отличием, что мое решение будет построено на основе пакета Open XML SDK версии 2. </P><H2>Документ </H2><P>Представим себе, что имеется документ, содержащий несколько примечаний, и некоторые из них могут включать изображения. Открыв соответствующий пакет, вы заметите, что в нашем текстовом документе с примечаниями имеется следующее содержимое: </P><UL><LI>Документ будет включать раздел примечаний с содержимым каждого примечания. </LI><LI>Раздел примечаний также может содержать ссылки на другие разделы, связанные с данным примечанием. Например, если примечание содержит изображение, раздел примечаний будет ссылаться на раздел изображений. </LI><LI>Главный раздел документа будет содержать ссылки на примечания посредством элементов ссылки на примечание. </LI><LI>Области, связанные с примечаниями, определяются в главном разделе с помощью начального и конечного элементов диапазона примечаний. </LI></UL><P>На следующем снимке экрана показан пример документа с примечаниями: </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/020609_1959_RemovingCom2.png" mce_src="https://zeyadrajabi.members.winisp.net/020609_1959_RemovingCom2.png"> </P><H2>Решение </H2><P>Для удаления примечаний из текстового документа потребуется выполнить следующие действия: </P><OL><LI>Открыть текстовый документ с помощью пакета Open XML SDK. </LI><LI>Получить доступ к главному разделу документа, из которого можно перейти ко всем другим разделам пакета. </LI><LI>Удалить раздел примечаний и все разделы, на которые в нем имеются ссылки. </LI><LI>Найти в главном разделе документа все элементы, связанные с примечаниями. </LI><LI>Удалить все найденные элементы. </LI><LI>Сохранить изменения документа. </LI></OL><P>В моей демонстрации будет использоваться <A href="https://go.microsoft.com/fwlink/?LinkId=127912" mce_href="https://go.microsoft.com/fwlink/?LinkId=127912">пакет SDK версии 2</A>. </P><P>Если вы хотите отслеживать все этапы работы непосредственно по коду, наше решение можно без труда загрузить <A href="https://zeyadrajabi.members.winisp.net/sourcecode/RemoveComments.zip" mce_href="https://zeyadrajabi.members.winisp.net/sourcecode/RemoveComments.zip">здесь</A>. </P><H2>Код </H2><P>В следующем фрагменте кода реализованы все шесть задач, рассмотренных выше в разделе <A href="https://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;sectionid=4689&amp;postid=9402790#_Solution" mce_href="https://blogs.msdn.com/controlpanel/blogs/posteditor.aspx?SelectedNavItem=Posts&amp;sectionid=4689&amp;postid=9402790#_Solution">Решение</A>. В этом коде используются некоторые результаты, полученные в записях <A href="https://blogs.msdn.com/brian_jones/archive/2009/01/28/traversing-in-the-open-xml-dom.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/01/28/traversing-in-the-open-xml-dom.aspx">Переходы в модели DOM пакета Open XML SDK</A> и <A href="https://blogs.msdn.com/brian_jones/archive/2009/01/12/open-xml-sdk-the-basics.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/01/12/open-xml-sdk-the-basics.aspx">Open XML SDK: основные сведения</A>. В частности, для поиска конкретных элементов, связанных с примечаниями, используется метод Descendants(), а для работы с этими элементами — универсальный класс OpenXmlElement. Кроме того, необходимо заметить, что при удалении раздела с помощью пакета Open XML SDK вместе с этим разделом удаляются все разделы, на которые в нем имеются ссылки. </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 613px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> RemoveComments(<SPAN style="COLOR: blue">string</SPAN> filename) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Open up the document </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">using</SPAN> (<SPAN style="COLOR: #2b91af">WordprocessingDocument</SPAN> myDoc = <SPAN style="COLOR: #2b91af">WordprocessingDocument</SPAN>.Open(filename, <SPAN style="COLOR: blue">true</SPAN>)) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Access main document part </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">MainDocumentPart</SPAN> mainPart = myDoc.MainDocumentPart; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Delete the comment part, plus any other part referenced, like image parts </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">mainPart.DeletePart(mainPart.WordprocessingCommentsPart); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Find all elements that are assoicated with comments </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">IEnumerable</SPAN>&lt;<SPAN style="COLOR: #2b91af">OpenXmlElement</SPAN>&gt; elementList = mainPart.Document.Descendants() </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.Where(el =&gt; el <SPAN style="COLOR: blue">is</SPAN> <SPAN style="COLOR: #2b91af">CommentRangeStart</SPAN> || </SPAN></DIV><DIV style="MARGIN-LEFT: 180pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">el <SPAN style="COLOR: blue">is</SPAN> <SPAN style="COLOR: #2b91af">CommentRangeEnd</SPAN> || </SPAN></DIV><DIV style="MARGIN-LEFT: 180pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">el <SPAN style="COLOR: blue">is</SPAN> <SPAN style="COLOR: #2b91af">CommentReference</SPAN>); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Delete every found element </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: #2b91af">OpenXmlElement</SPAN> e <SPAN style="COLOR: blue">in</SPAN> elementList) </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">e.Remove(); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Save changes </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">mainPart.Document.Save(); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><H2>Заключение </H2><P>Объединив и запустив итоговый код, мы получим документ, полностью очищенный от примечаний. Великолепно! </P><P>Взгляните на снимок экрана, на котором показан окончательный документ: </P><P><IMG alt="" src="https://zeyadrajabi.members.winisp.net/020609_1959_RemovingCom3.png" mce_src="https://zeyadrajabi.members.winisp.net/020609_1959_RemovingCom3.png"> </P><P>Зияд Раджаби (Zeyad Rajabi)</P><img src="https://blogs.msdn.com/aggbug.aspx?PostID=9402790" width="1" height="1"><p>Это локализованная запись блога. Исходную статью можно найти по адресу <a href='https://blogs.msdn.com/brian_jones/archive/2009/02/06/removing-comments-from-a-wordprocessing-document-programmatically.aspx'>https://blogs.msdn.com/brian_jones/archive/2009/02/06/removing-comments-from-a-wordprocessing-document-programmatically.aspx</a>.]]></content:encoded>
    </item>
    <item>
      <title>Объединение нескольких презентаций PowerPoint</title>
      <link>https://docs.microsoft.com/archive/blogs/brian_jones_ru/113</link>
      <pubDate>Thu, 02 Jul 2009 17:37:01 GMT</pubDate>
      <dc:creator><![CDATA[OfficeLocalization]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/brian_jones_ru/2009/07/02/113/</guid>
      <description><![CDATA[Я хочу предупредить вас, друзья, что в настоящее время мы работаем над устранением ряда неполадок на...]]></description>
      <content:encoded><![CDATA[<P><EM>Я хочу предупредить вас, друзья, что в настоящее время мы работаем над устранением ряда неполадок на сервере, и поэтому в некоторых предыдущих записях могут не отображаться изображения или ссылки на исходный код. Надеюсь, эти неполадки будут скоро исправлены.</EM> </P><P>В своей предыдущей записи я показал вам <A href="https://blogs.msdn.com/brian_jones/archive/2008/12/08/the-easy-way-to-assemble-multiple-word-documents.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2008/12/08/the-easy-way-to-assemble-multiple-word-documents.aspx">простой способ объединения нескольких документов Word</A>. Сегодня я расскажу, как можно объединить несколько презентаций PowerPoint. </P><H2>Решение </H2><P>Для объединения двух презентаций — исходной и целевой — потребуется выполнить следующие действия: </P><OL><LI>Открыть целевую презентацию с помощью пакета Open XML SDK и получить доступ к главному разделу презентации. </LI><LI>Открыть исходную презентацию и получить доступ к ее главному разделу. </LI><LI>Добавить все слайды исходной презентации в целевую презентацию, сохранив их порядок. </LI><LI>Проверить наличие отношения между главным разделом целевой презентации и разделом макета образца слайдов для каждого добавленного слайда. </LI><LI>Проверить наличие в главном разделе целевой презентации ссылки на каждый добавленный раздел макета образца слайдов. </LI><LI>Проверить наличие в главном разделе целевой презентации ссылки на каждый добавленный раздел слайдов. </LI><LI>Выполнить операцию очистки, чтобы обеспечить присвоение всем ссылкам на разделы макета слайдов уникальных идентификаторов. </LI><LI>Сохранить изменения целевой презентации. </LI></OL><P>В моей демонстрации будет использоваться <A href="https://go.microsoft.com/fwlink/?LinkId=127912" mce_href="https://go.microsoft.com/fwlink/?LinkId=127912">пакет SDK версии 2</A>. </P><P>Чтобы более наглядно представить изложенный здесь материал, начнем работать со следующими двумя презентациями, в каждой из которых содержится по три слайда: </P><DIV><TABLE class="" style="BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 319px"><COL style="WIDTH: 319px"></COLGROUP><TBODY vAlign=top><TR style="BACKGROUND: #edf2f8"><TD class="" style="BORDER-RIGHT: #4f81bd 1pt solid; PADDING-RIGHT: 7px; BORDER-TOP: #4f81bd 1pt solid; PADDING-LEFT: 7px; BORDER-LEFT: #4f81bd 1pt solid; BORDER-BOTTOM: #4f81bd 1pt solid"><P><SPAN style="COLOR: black"><STRONG>Destination Deck</STRONG></SPAN></P></TD><TD class="" style="BORDER-RIGHT: #4f81bd 1pt solid; PADDING-RIGHT: 7px; BORDER-TOP: #4f81bd 1pt solid; PADDING-LEFT: 7px; BORDER-LEFT: medium none; BORDER-BOTTOM: #4f81bd 1pt solid"><P><SPAN style="COLOR: black"><STRONG>Source Deck</STRONG></SPAN></P></TD></TR><TR style="BACKGROUND: #a7bfde"><TD class="" style="BORDER-RIGHT: #4f81bd 0.75pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: #4f81bd 1pt solid; BORDER-BOTTOM: #4f81bd 1pt solid"><P><IMG alt="Destination deck with three slides" src="https://stunna42.members.winisp.net/030509_1909_HowtoAssemb1.png"> </P></TD><TD class="" style="BORDER-RIGHT: #4f81bd 1pt solid; PADDING-RIGHT: 7px; BORDER-TOP: medium none; PADDING-LEFT: 7px; BORDER-LEFT: medium none; BORDER-BOTTOM: #4f81bd 1pt solid"><P><IMG alt="Source deck with three slides" src="https://stunna42.members.winisp.net/030509_1909_HowtoAssemb2.png"> </P></TD></TR></TBODY></TABLE></DIV><P>Если вы хотите отслеживать все этапы работы непосредственно по коду, наше решение можно без труда загрузить <A href="https://stunna42.members.winisp.net/sourcecode/AssemblePowerPointDecks.zip" mce_href="https://stunna42.members.winisp.net/sourcecode/AssemblePowerPointDecks.zip">здесь</A>. </P><H2>Код </H2><P>Как указывалось в разделе "Решение" выше, для выполнения первых трех шагов необходимо открыть целевую и исходную презентации, чтобы добавить каждый слайд исходной презентации в целевую презентацию. Взгляните на фрагмент кода, в котором реализуется выполнение этих задач: </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 671px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> MergeDecks(<SPAN style="COLOR: blue">string</SPAN> sourceDeck, <SPAN style="COLOR: blue">string</SPAN> destDeck) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">int</SPAN> id = 1; </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Open up the destination deck </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">using</SPAN> (<SPAN style="COLOR: #2b91af">PresentationDocument</SPAN> myDestDeck = <SPAN style="COLOR: #2b91af">PresentationDocument</SPAN>.Open(destDeck, <SPAN style="COLOR: blue">true</SPAN>)) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">PresentationPart</SPAN> destPresPart = myDestDeck.PresentationPart; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Open up the source deck </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">using</SPAN> (<SPAN style="COLOR: #2b91af">PresentationDocument</SPAN> mySourceDeck = <SPAN style="COLOR: #2b91af">PresentationDocument</SPAN>.Open(sourceDeck, <SPAN style="COLOR: blue">true</SPAN>)) </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">PresentationPart</SPAN> sourcePresPart = mySourceDeck.PresentationPart; </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Need to get a unique ids for slide master and slide lists //(will use these later) </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">uniqueId = GetMaxIdFromChild(destPresPart.Presentation.SlideMasterIdList); </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">uint</SPAN> maxSlideId = GetMaxIdFromChild(destPresPart.Presentation.SlideIdList); </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Copy each slide in my source deck in order to my destination deck </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: #2b91af">SlideId</SPAN> slideId <SPAN style="COLOR: blue">in</SPAN> </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">sourcePresPart.Presentation.SlideIdList) </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SlidePart</SPAN> sp; </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SlidePart</SPAN> destSp; </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SlideMasterPart</SPAN> destMasterPart; </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">string</SPAN> relId; </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SlideMasterId</SPAN> newSlideMasterId; </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SlideId</SPAN> newSlideId; </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//come up with a unique relationship id </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">id++; </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">sp = (<SPAN style="COLOR: #2b91af">SlidePart</SPAN>)sourcePresPart </SPAN></DIV><DIV style="MARGIN-LEFT: 180pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">.GetPartById(slideId.RelationshipId); </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">relId = sourceDeck.Remove(sourceDeck.IndexOf(<SPAN style="COLOR: #a31515">'.'</SPAN>)) + id; </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">destSp = destPresPart.AddPart&lt;<SPAN style="COLOR: #2b91af">SlidePart</SPAN>&gt;(sp, relId); </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: green">//Add the slide part to the destination deck</SPAN>&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">SlidePart</SPAN> destSp = destPresPart.AddPart&lt;<SPAN style="COLOR: #2b91af">SlidePart</SPAN>&gt;(sp, relId); </SPAN></DIV><DIV style="MARGIN-LEFT: 144pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">... </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Для проверки того, что все слайды исходной презентации добавлены в правильном порядке, необходимо перебрать список идентификаторов слайдов. Кроме того, обратите внимание, что нам потребовалось <A href="https://blogs.msdn.com/brian_jones/archive/2009/02/19/how-to-copy-a-worksheet-within-a-workbook.aspx" mce_href="https://blogs.msdn.com/brian_jones/archive/2009/02/19/how-to-copy-a-worksheet-within-a-workbook.aspx">использовать преимущества метода AddPart</A>, который позволяет добавлять не только раздел слайдов, но и все разделы, на которые в нем имеются ссылки. </P><P>На данном этапе мы лишь выполнили импорт раздела слайдов в целевую презентацию. Нашей следующей задачей будет установление отношения между главным разделом целевой презентации и добавленным разделом образцов слайдов. И здесь мы воспользуемся возможностями метода AddPart для добавления этого отношения с помощью следующего кода (метод AddPart устанавливает отношения, если раздел уже существует в пакете): </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Master part was added, but now we need to make sure the relationship is in place </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">destMasterPart = destSp.SlideLayoutPart.SlideMasterPart; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">destPresPart.AddPart(destMasterPart);</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Наш следующий шаг заключается в добавлении списка идентификаторов разделов образцов слайдов и идентификаторов слайдов в соответствующие списки главного раздела целевой презентации. Идентификаторы, указанные в каждом из этих списков, должны быть уникальными. Кроме того, существует дополнительное ограничение, которое состоит в том, что списки идентификаторов образцов слайдов и идентификаторов макетов слайдов должны содержать только уникальные значения, которые больше или равны 2147483684. Для выполнения этих требований уникальности необходим метод, который позволяет извлекать текущее максимальное значение идентификатора в списке. В таком случае при каждом добавлении нового элемента в список нам будет достаточно прибавить единицу к максимальному значению идентификатора. Ниже показан универсальный метод извлечения максимального значения из набора дочерних элементов. </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">uint</SPAN> GetMaxIdFromChild(<SPAN style="COLOR: #2b91af">OpenXmlElement</SPAN> el) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">uint</SPAN> max = 1; </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Get max id value from set of children </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: #2b91af">OpenXmlElement</SPAN> child <SPAN style="COLOR: blue">in</SPAN> el.ChildElements) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: #2b91af">OpenXmlAttribute</SPAN> attribute = child.GetAttribute(<SPAN style="COLOR: #a31515">"id"</SPAN>, <SPAN style="COLOR: #a31515">""</SPAN>); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">&nbsp;&nbsp;&nbsp;&nbsp; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">uint</SPAN> id = <SPAN style="COLOR: blue">uint</SPAN>.Parse(attribute.Value); </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">if</SPAN> (id &gt; max) </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">max = id; </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">return</SPAN> max; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Этот метод вызывается перед первым проходом цикла, чтобы получить соответствующие уникальные идентификаторы для списков идентификаторов разделов образцов слайдов и идентификаторов слайдов. После получения уникальных идентификаторов можно добавить идентификаторы раздела образцов слайдов и идентификаторы слайдов в соответствующие списки главного раздела целевой презентации. Ниже показан код, необходимый для добавления идентификаторов в эти два списка. </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Add slide master to slide master list </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">uniqueId++; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">newSlideMasterId = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">SlideMasterId</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">newSlideMasterId.RelationshipId = destPresPart.GetIdOfPart(destMasterPart); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">newSlideMasterId.Id = uniqueId; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Add slide to slide list </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">maxSlideId++; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">newSlideId = <SPAN style="COLOR: blue">new</SPAN> <SPAN style="COLOR: #2b91af">SlideId</SPAN>(); </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">newSlideId.RelationshipId = relId; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">newSlideId.Id = maxSlideId; </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">destPresPart.Presentation.SlideMasterIdList.Append(newSlideMasterId); destPresPart.Presentation.SlideIdList.Append(newSlideId); </SPAN></DIV></TD></TR></TBODY></TABLE></DIV><P>Мы почти закончили! Теперь нам осталось только проверить уникальность всех идентификаторов макетов слайдов. Как уже упоминалось, значения этих идентификаторов не должны совпадать со значениями списка идентификаторов разделов образцов слайдов. Кроме того, необходимо убедиться, что эти идентификаторы больше или равны 2147483684. Ниже показан метод, который перебирает все разделы образцов слайдов и устанавливает идентификаторы всех макетов слайдов, на которые имеются ссылки, простым увеличением значений идентификаторов на основе максимального значения uint, определенного на данный момент. </P><DIV style="MARGIN-LEFT: 36pt"><TABLE class="" style="BACKGROUND: #dbe5f1; BORDER-COLLAPSE: collapse" border=0><COLGROUP><COL style="WIDTH: 631px"></COLGROUP><TBODY vAlign=top><TR><TD class="" style="BORDER-RIGHT: black 0.5pt solid; PADDING-RIGHT: 7px; BORDER-TOP: black 0.5pt solid; PADDING-LEFT: 7px; BORDER-LEFT: black 0.5pt solid; BORDER-BOTTOM: black 0.5pt solid"><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">static</SPAN> <SPAN style="COLOR: blue">void</SPAN> FixSlideLayoutIds(<SPAN style="COLOR: #2b91af">PresentationPart</SPAN> presPart) </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: Courier New">//Need to make sure all slide layouts have unique ids </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: #2b91af">SlideMasterPart</SPAN> slideMasterPart <SPAN style="COLOR: blue">in</SPAN> presPart.SlideMasterParts) </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New"><SPAN style="COLOR: blue">foreach</SPAN> (<SPAN style="COLOR: #2b91af">SlideLayoutId</SPAN> slideLayoutId <SPAN style="COLOR: blue">in</SPAN> slideMasterPart.SlideMaster.SlideLayoutIdList) </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">{ </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">uniqueId++; </SPAN></DIV><DIV style="MARGIN-LEFT: 108pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">slideLayoutId.Id = (<SPAN style="COLOR: blue">uint</SPAN>)uniqueId; </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV style="MARGIN-LEFT: 72pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">slideMasterPart.SlideMaster.Save(); </SPAN></DIV><DIV style="MARGIN-LEFT: 36pt"><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">} </SPAN></DIV><DIV><SPAN style="FONT-SIZE: 10pt; FONT-FAMILY: Courier New">}</SPAN></DIV></TD></TR></TBODY></TABLE></DIV><H2>Заключение </H2><P>Собрав вместе все показанные фрагменты и запустив итоговый код, мы получим презентацию, содержащую шесть слайдов в правильном порядке. </P><P>Взгляните на снимок экрана, на котором показана окончательная презентация: </P><P><IMG alt="Итоговая объединенная презентация с шестью слайдами" src="https://stunna42.members.winisp.net/030509_1909_HowtoAssemb3.png"> </P><P>Зияд Раджаби (Zeyad Rajabi)</P><img src="https://blogs.msdn.com/aggbug.aspx?PostID=9460410" width="1" height="1"><p>Это локализованная запись блога. Исходную статью можно найти по адресу <a href='https://blogs.msdn.com/brian_jones/archive/2009/03/05/how-to-assemble-multiple-powerpoint-decks.aspx'>https://blogs.msdn.com/brian_jones/archive/2009/03/05/how-to-assemble-multiple-powerpoint-decks</a>.]]></content:encoded>
    </item>
  </channel>
</rss>