Как стать автором
Обновить

Опыт использования VSTO для PowerPoint 2007

Время на прочтение6 мин
Количество просмотров1.5K
Я делаю много презентаций, и часто нужно показать код «по частям», то есть показать ход мысли в процессе последовательного написния кода. К сожалению, PowerPoint не настроен для таких целей. Поэтому я решил написать расширение для PowerPoint 2007 которое автогенерировало бы последовательность слайдов с «прогрессивной разверткой» кода и комментариев. Собственно об этом и будет рассказ.

Идея


Сначала попробую объяснить идею. Есть у вас кусочек кода, скажем вот такой[1]:
public static T DeepCopy<T>(this IPrototype<T> obj)<br/>
{<br/>
  T copy;<br/>
  using (MemoryStream stream = new MemoryStream())<br/>
  {<br/>
    BinaryFormatter formatter = new BinaryFormatter();<br/>
    formatter.Serialize(stream, obj);<br/>
    stream.Seek(0, SeekOrigin.Begin);<br/>
    copy = (T)formatter.Deserialize(stream);<br/>
    stream.Close();<br/>
  }<br/>
  return copy;<br/>
}<br/>

Этот код хочется объяснить по частям на слайдах. Например, изначально можно показать вот это:
// создаем метод расширения
public static T DeepCopy<T>(this IPrototype<T> obj)<br/>
{<br/>

А потом, вот это:
// создаем метод расширения
public static T DeepCopy<T>(this IPrototype<T> obj)<br/>
{<br/>
  // создаем копию объекта
  T copy;<br/>

И так далее. Казалось бы – можно использовать и встроенную анимацию[2], но это негибко – ведь даже если вы прячете, например, кусочек кода, то место для него все равно будет выделено, что не есть хорошо. А что если нужно спрятать не параграф или строчку, а только пару букв (например, ключевое слово)? Вот как раз для этих целей я решил написать свой второй[3] add-in для PowerPoint.

Интерфейс


Дополнения для Office очень просто писать: для этого нужно воспользоваться дополнениями VSTO (Visual Studio Tools for Office). В студии появляются соответствующие типы проектов, из которых я выбрал PowerPoint 2007 Add-In:

Что очень радует, так это то что наш сгенерированный проект уже готов к использованию. В нем работает отладка по F5, и что приятно – даже если я не в студии, add-in остается в PowerPoint, что позволяет мне в свободное время «питаться своим же собачьим кормом».[4]
Поскольку в офисе используются ленточные контролы (ribbons), студия поддерживает работу именно с этими элементами управления. Для создания элементов ленточек есть даже специальный дизайнер:

Мне для интерфейса нужны былa всего одна кнопочка, что существенно упростило задачу (upd: теперь их уже 3):

Модальный интерфейс


У студии есть проблема (не знаю, может решили в 2010й), что в проект расширений, будь то расширений студии или офиса, нельзя добавить окна WPF. Обычно я решаю эту проблему с помощью отдельной сборки, но в данном случае захотелось попробовать пописать на WinForms, причем для интерфейса выбрал бесплатные (и достаточно красивые) контролы Krypton. Вот как это дело выглядит в завершенном варианте:

Неплохо, не правда ли? Все это бесплатно, и доступно тут. А вот то, как открывается окно из add-in’а – это стоит объяснить. Помните наш риббон? Так вот – в самом классе add-in’а он нигде не регистрируется! Риббон создается автоматически! А дальше все просто – к нашей кнопочке подвязано событие, которое собственно и делает предсказуемый вызов ShowDialog().

Работа со слайдами


Поскольку внутренняя логика add-in’а достаточно скучна, расскажу как программным путем создавать слайды в презентации. Прежде всего, нужно где-то держать ссылку на сам PowerPoint. Для этого, я просто создал статическую переменную и закэшировал в нее то значение, что получил при инициализации add-in’а:

public static Application App;<br/>
 <br/>
private void OnStartup(object sender, EventArgs e)<br/>
{<br/>
  App = Application;<br/>
  if (ApplicationStartedEvent != null)<br/>
    ApplicationStartedEvent(thisnull);<br/>
}<br/>

Теперь наш обработчик кнопки (ну, тот что в риббоне) может получить эту же ссылку, а из нее – «активную» презентацию пользователя (т.е. ту, с которой пользователь работает):

var app = ThisAddIn.App;<br/>
var p = app.ActivePresentation;<br/>

Добавить новый слайд к презентации – проще простого. Помните типы layout’ов которые можно выбрать для слайда? Так вот, тут они—enum’ы, так что все очень просто:

Slide s = p.Slides.Add(<br/>
  1+p.Slides.Count, // вставить последним
  PpSlideLayout.ppLayoutText // одно большое текстовое поле
);<br/>

Дальше – еще проще. У слайда с нашим раскладом ppLayoutText есть заголовок и главное текстовое поле. Эти объекты доступны в коллекции Shapes слайда (не забывайте, что коллекции индексируются с единицы, а не с нуля). Вот например как можно выставить текст заголовка:
var title = s.Shapes[1];<br/>
title.TextFrame2.TextRange.Text = cff.ApplicationSettings.SlideTitle;<br/>

К слову замечу что использование ключевого слова var очень помогает при разработке. Что еще заметно, так это то, что при написании всего add-in’а мне не разу не пришлось использовать значение missing, которое является одним из главных неудобств при работе с расширением офиса. В C#4 такое проблемы конечно же больше нет.
Вот пример того, как манипулировать свойствами текствой рамки. В моем случае я выставляю заданный пользователем шрифт а также убираю дефолтные поля и «буллиты»:
var code = s.Shapes[2].TextFrame2.TextRange;<br/>
code.ParagraphFormat.FirstLineIndent = 0;<br/>
code.ParagraphFormat.Bullet.Visible = MsoTriState.msoFalse;<br/>
code.Font.CopyFrom(cff.ApplicationSettings.CodeFont);<br/>
code.ParagraphFormat.RightIndent = 0;<br/>
code.ParagraphFormat.LeftIndent = 0;<br/>
code.ParagraphFormat.SpaceBefore = 0;<br/>

Заметьте что для шрифтов используется метод расширения. Проблема в том, что Office использует свой тип Font2, а конверсия из System.Drawing.Font конечно же не определена. Еще заметьте что в офисе, типы true и false – это enum’ы, чтобы можно было выставить значения «да», «нет» и «не задано». Опять же, нетрудно при желании определить конверсию из нашего bool в офисный MsoTriState.

Работа с текстом


Как вы уже догадались, текст кладется в объект типа TextFrame2. Когда вы добавляете в рамку текст, вы получаете ссылку на тот отрезок кода, который добавили:
var range = textarea.TextFrame2.TextRange.InsertAfter(finalText);<br/>

Теперь можно менять вкусовые качества этого отрезка текста – такие как шрифт или цвет:
range.Font.Fill.ForeColor.RGB = settings.EmphasisColor.ToRgb();<br/>
range.Font.CopyFrom(settings.EmphasisFont ?? settings.CodeFont);<br/>

Копирование шрифтов мы уже обсудили, а с цветом – та же проблема. Если использовать функцию ToArgb() которая уже встроена, то получите цвет «наизнанку». Пришлось реализовывать конверсию вручную:
public static int ToRgb(this Color color)<br/>
{<br/>
  return (color.A << 24) + (color.B << 16) + (color.G << 8) + color.R;<br/>
}<br/>

Тут пора бы уже и закончить, только вот хочу сделать одно предупреждение: если вы сделали параграф определенного цвета, то следующий параграф или кусочек кода будет такой же. Поэтому, когда строите текст из составных частей, сначала закэшируйте дефолтные значения, и применяйте их к каждому отрезку, который хотите добавить.

Заключение


Работа с инфраструктурой VSTO оказалась весьма несложной, и результаты использования add-in’а скоро можно будет увидеть на моих презентациях в Spbalt.net, Ineta, ActiveMesa и других организациях. А если вас вдруг заинтересовал проект, то результат работы add-in’а а также исходный код можно скачать тут.

Заметки


  1. Кстате, этот кусочек кода был использован для реализации паттерна Prototype в add-in’е. Хотя сейчас мне кажется что это перебор – можно было воспользоваться и MemberwiseClone().
  2. На самом деле – нет, нельзя. ИМХО, презентации нужно выкладывать в PDF и только в PDF (или вы думаете что пользователей Linux программирование не интересует?), а при конверсии в PDF анимация PP теряется. Поэтому подход, показаный тут, идеален для таких групп как Spbalt.net где материалы докладов только в PDF и выставляются.
  3. Первым расширением PP которое я написал была визуализация нейронных сетей. Это было 3 года назад, еще для 2003 офиса.
  4. Эту фразу (eating our own dogfood) любят использовать сотрудники Microsoft когда говорят про то, что используют свою же инфраструктуру для разработок.
Теги:
Хабы:
+5
Комментарии0

Публикации

Изменить настройки темы

Истории

Работа

.NET разработчик
74 вакансии

Ближайшие события

Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн