ADN Open CIS
Сообщество программистов Autodesk в СНГ

05/09/2013

Выбор подходящего вида при вставке семейства

Мэт Тэйлор (Matt Taylor) из компании WSP поднял одну важную проблему, связанную с использованием метода PromptForFamilyInstancePlacement в Revit 2014.

Также он пошел верным путем, предложив и реализовав решение этой проблемы.

Вопрос: Одним из важных нововведений в Revit API 2014 является возможность вызова внешней команды при активном Диспетчере проекта. Если Диспетчер проектов активен, и вызывается команда, которая использует метод PromptForFamilyInstancePlacement, то возникнет ошибка, так как будет произведена попытка вставки семейства на активный вид. Активным видом в этом случае является Диспетчер проекта и, очевидно, что в него семейство вставить нельзя.

В справке по API для метода PromptForFamilyInstancePlacement отмечается, что пользователь не может сменить вид во время операции вставки семейства.

Если у вас только один открытый вид, в который вы можете вставить семейство, то довольно легко сделать его активным перед вызовом метода PromptForFamilyInstancePlacement. Но что делать если их много? Как мне получить последний активный вид, который был до активации Диспетчера проекта?

Может быть что-то реализовать в обработке события ViewActivated? Или предложить пользователю выбрать вид, прежде чем вызывать метод PromptForFamilyInstancePlacement? Но для Revit 2013 и ниже это действие выглядит не логичным.

Ответ: Я думаю вариант с обработкой события ViewActivated вполне жизнеспособен и не очень сложен в реализации. Нужно всего лишь в обработке этого события сохранять какие виды были активными. Перед вызовом PromptForFamilyInstancePlacement активировать последний вид, в котором можно выполнить операцию вставки семейства. Думаю, это решит вашу проблему.

Отклик на ответ: Вот архив проекта с решением проблемы. Большинство кода взято из вашего блога, хоть и на VB.NET.

Реализация оказалась гораздо сложней, чем я думал.

В методе OnStartup инициализируем словарь, содержащий последний валидный, для метода PromptForFamilyInstancePlacement, вид для каждого документа. И подпишемся на событие ViewActivated.

Код - VB.NET: [Выделить]
  1.     ''' <summary>
  2.     ''' Map document title to last valid view element id
  3.     ''' </summary>
  4.     Public Shared viewHash As Hashtable
  5.  
  6.     Public Function OnStartup( _
  7.       ByVal application As UIControlledApplication) _
  8.     As Result Implements IExternalApplication.OnStartup
  9.  
  10.         Try
  11.             viewHash = New Hashtable
  12.  
  13.             AddHandler application.ViewActivated,
  14.               AddressOf OnViewActivated
  15.  
  16.             Return Result.Succeeded
  17.  
  18.         Catch ex As Exception
  19.  
  20.             Return Result.Failed
  21.         End Try
  22.  
  23.     End Function
  24.  

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

Код - VB.NET: [Выделить]
  1.  
  2.     Private Shared Function ViewDescription( _
  3.   ByVal v As View) As String
  4.  
  5.         Return String.Format(
  6.           "view '{0}' in document '{1}'",
  7.           v.Name, v.Document.Title)
  8.  
  9.     End Function
  10.  
  11.     Private Sub OnViewActivated( _
  12.       ByVal sender As Object,
  13.       ByVal e As ViewActivatedEventArgs)
  14.  
  15.         Dim docTitle As String = e.Document.Title
  16.         Dim vPrevious As View = e.PreviousActiveView
  17.         Dim vCurrent As View = e.CurrentActiveView
  18.         If Not (vCurrent.ViewType = ViewType.SystemBrowser _
  19.                 OrElse vCurrent.ViewType = ViewType.ProjectBrowser) Then
  20.             If viewHash.ContainsKey(docTitle) Then
  21.                 viewHash.Item(docTitle) = vCurrent.Id
  22.             Else
  23.                 viewHash.Add(docTitle, vCurrent.Id)
  24.             End If
  25.         End If
  26.  
  27.         Dim s As String = If(
  28.           (vPrevious Is Nothing),
  29.           "no view at all",
  30.           "previous " + ViewDescription(vPrevious))
  31.  
  32.         Debug.Print(
  33.           String.Format(
  34.             "Switching from {0} to new {1}.",
  35.             s, ViewDescription(vCurrent)))
  36.  
  37.     End Sub
  38.  

Зная эту информацию, мы всегда можем переключиться на нужный вид, перед вызовом PromptForFamilyInstancePlacement .

Код - VB.NET: [Выделить]
  1.         ' According to the help for 
  2.         ' PromptForFamilyInstancePlacement:
  3.         ' "Users are not permitted to change the active 
  4.         ' view during this placement operation (the 
  5.         ' operation will be completed)."
  6.         ' Here's the fix, which only needs to work for 2014.
  7.         ' (With previous versions, the ribbon items are 
  8.         ' greyed out if the project browser is active.)
  9.  
  10.         Dim actView As DB.View = doc.ActiveView
  11.  
  12.         If actView.ViewType = DB.ViewType.SystemBrowser _
  13.           OrElse actView.ViewType = DB.ViewType.ProjectBrowser Then
  14.  
  15.             ' Get stored view id.
  16.  
  17.             If AppCommand.viewHash.ContainsKey(doc.Title) Then
  18.  
  19.                 Dim prevValidViewId As DB.ElementId _
  20.                   = AppCommand.viewHash.Item(doc.Title)
  21.  
  22.                 Dim elem As DB.Element = doc.GetElement(
  23.                   prevValidViewId)
  24.  
  25.                 If elem IsNot Nothing Then
  26.                     Dim view As DB.View = TryCast(elem, DB.View)
  27.                     If view IsNot Nothing Then
  28.  
  29.                         ' TODO: Check that view is valid for the 
  30.                         ' placement of this type of family symbol, 
  31.                         ' otherwise get another view.
  32.                         ' (Likely to be the case, as the user 
  33.                         ' will normally click a ribbon item as 
  34.                         ' part of the context of what they're doing.)
  35.  
  36.                         docUI.ActiveView = view
  37.  
  38.                     End If
  39.                 End If
  40.  
  41.             End If
  42.         End If
  43.  
  44.         docUI.PromptForFamilyInstancePlacement(
  45.           FamilySymbol)
  46.  

Спасибо Мэту за то что указал на существование проблемы и за элегантное ее решение!

Источник: http://thebuildingcoder.typepad.com/blog/2013/09/set-a-suitable-view-for-family-instance-placement.html

Обсуждение: http://adn-cis.org/forum/index.php?topic=199

Опубликовано 05.09.2013