В формулах шейп-листа часто используются ссылки на другие ячейки. Ячейки того же шейпа, другого шейпа, страницы, документа. Однако, как показывает практика, такие ссылки работают не всегда. Например, в старших версиях Visio может не работать ссылка на документ.

Тестовые конструкции

Рассмотрим формулу TheDoc!User.a.

Сделаем 4 мастер-шейпа во внешнем трафарете tstDoc.vssx и исследуем поведение копий этих мастер-шейпов при опускании их на страницу рисунка. Теоретически все эти шейпы должны вести себя одинаково – передавать данные из ячейки User.a документа в текстовое поле шейпа.

Вариант 1. Одиночная ссылка

В простейшем случае она не вызывает проблем. Здесь шейп содержит поле, непосредственно ссылающееся на ячейку User.a в документе. При обновлении значения в документе сразу же обновляется текст шейпа.

Вариант 2. Двухзвенная цепочка

Усложним конструкцию. Добавим в шейп ячейку User.a и удлиним цепочку ссылок. Теперь данные документа поступают сначала в User.a шейпа и только потом в текстовое поле шейпа.

Вот и появились проблемы. При обновлении данных в документе текст шейпа не изменяется. Это ошибка, нарушающая законы ссылок в Visio.

Отложим объяснение причин и рассмотрим еще две конструкции (более сложные).

Вариант 3. Поле внутри группы

Пусть в качестве промежуточной ячейки используется не ячейка того же шейпа, а ячейка User.a группы.

В этом варианте обновление текста в шейпе тоже не происходит. Собственно вариант сильно напоминает предыдущий, только шейпов стало больше.

Вариант 4. Шейп с авторемонтом

Наконец, рассмотрим такую конструкцию

Здесь в группе задействована ячейка EventDrop, которая при опускании мастер-шейпа на страницу рисунка обновляет формулу в ячейке User.a.

Вот теперь шейп опять ведет себя так, как положено по документации – обновление данных документа сразу же проявляется в тексте шейпа.

Эксперимент

Собственно эксперимент. Перебрасываем все 4 мастера на страницу рисунка. Для начала все 4 шейпа отображают одинаковый текст (который в данный момент находится в TheDoc!User.a).

Справа показаны имена мастер-шейпов.

Теперь открываем шейп-лист документа и меняем значение ячейки User.a на test_2.

Два шейпа правильно передали новое значение данных документа, а два остались неизменными.

Рассуждения

В процессе обсуждения схожей ситуации на форуме было подмечено, что критически важно, является ли формула в промежуточной ячейке наследуемой или локальной.

В варианте 1 промежуточной ячейки вообще нет. Ссылка работает верно даже с наследуемой формулой.

В вариантах 2 и 3 промежуточная ячейка есть и формула в ней наследуемая (и на картинке она черного цвета). В этом случае цепочка передачи данных рвется. Обновление не работает.

В варианте 4 в момент опускания мастер-шейпа на страницу рисунка срабатывает функция SETF в ячейке EventDrop и прописывает в ячейку User.a ту же формулу, что и в мастер-шейпе. Но эта формула уже присутствует локально. Если посмотреть шейп-лист копии, то формула будет уже синего цвета. И это восстанавливает транспорт данных.

В принципе, отличия в поведении объяснимы. Шейп-копия просто не содержит наследуемых ячеек. Их нет в файле. Формулы для этих ячеек притягиваются из мастер-шейпов. И вот в длинных цепочках ссылок сам факт обновления теряется. Формулы нет, значит и обновления нет, а в мастер-шейпе посмотреть забыли. Напомню, что в короткой цепочке (вариант 1) обновление происходит нормально.

Другое решение 1

В процессе обсуждения на форуме предлагалось удалять мастер-шейп в трафарете документа. На первый взгляд результат похож - ссылающаяся формула тоже станет локальной. Но связь с мастер-шейпом будет потеряна и обращение к меню Shape Name покажет нам no master. Значит если пользователь когда-то захочет подправить мастер-шейп в трафарете, то изменения не проникнут в копии шейпа в документе. Останется только удалять их и заменять на копии от нового мастера.

В отличие от этого, ремонт по варианту 4 сохраняет связь с мастер-шейпом. Если, например, перекрасить мастер-шейп в трафарете документа или заменить логотип (в составе группы), то изменения будут переданы во все копии.

Другое решение 2

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

Программа может быть примерно такой:

Sub LocalForm()
 Dim shp As Visio.Shape
 Set shp = ActivePage.Shapes(1)
 intCounter = shp.RowCount(242)
 For i = 0 To intCounter - 1
  If shp.CellsSRCExists(242, i, 0, 0) Then
    Set vsoCell = shp.CellsSRC(242, i, 0)
    t2 vsoCell
  End If
 Next
End Sub

Sub t2(ByVal cll As Visio.Cell)
 If cll.Formula <> "" Then
 If cll.IsInherited Then
  cll.Formula = cll.Formula
  acell = cll.Precedents
  For intCounter = LBound(acell) To UBound(acell)
   Set vsoCell = acell(intCounter)
   Debug.Print cll.Name & " depends on " & vsoCell.Name & " F=" & cll.Formula
   t2 vsoCell
  Next
  End If
 Else
  Debug.Print cll.Name & " no formula"
 End If
End Sub

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

Выводы

1. При разработке трафаретов следует очень осторожно применять цепочки наследования (несколько последовательных ссылок в формулах), они могут не работать.

2. Для длинных цепочек желательно предусматривать перевод наследуемых формул в локальные. Это можно закладывать в конструкцию шейпов, например с использованим SETF в событии EventDrop, или используя программные методы.

Трафарет для тестирования