2013-12-10 3 views
1

Я пытаюсь создать свой первый плагин Revit.Поместите один экземпляр семейства в проект Revit с помощью плагина C#

Я использую Revit 2014, и я хочу разместить экземпляр SINGLE семейства, загруженного из файла. Я на самом деле с помощью этого кода:

[TransactionAttribute(TransactionMode.Manual)] 
[RegenerationAttribute(RegenerationOption.Manual)] 
public class InsertFamily : IExternalCommand 
{ 
    readonly List<ElementId> _addedElementIds = new List<ElementId>(); 

    public Result Execute(
     ExternalCommandData commandData, 
     ref string message, 
     ElementSet elements) 
    { 
     UIApplication uiApp = commandData.Application; 
     Document document = uiApp.ActiveUIDocument.Document; 

     FamilySymbol family = null; 
     bool good = false; 
     using (var trans = new Transaction(document, "inserting family")) 
     { 
      trans.Start(); 
      good = document.LoadFamilySymbol(@"my file path.rfa", "my type", new FamilyLoadingOverwriteOption(), out family); 
      trans.Commit(); 
     } 
     if (good && family != null) 
     { 

      _addedElementIds.Clear(); 

      uiApp.Application.DocumentChanged += applicationOnDocumentChanged; 

      uiApp.ActiveUIDocument.PromptForFamilyInstancePlacement(family); 

      uiApp.Application.DocumentChanged -= applicationOnDocumentChanged; 

     } 
     return Result.Succeeded; 
    } 

    private void applicationOnDocumentChanged(object sender, DocumentChangedEventArgs documentChangedEventArgs) 
    { 
     _addedElementIds.AddRange(documentChangedEventArgs.GetAddedElementIds());   
    } 
} 



class FamilyLoadingOverwriteOption : IFamilyLoadOptions 
{ 
    public bool OnFamilyFound(bool familyInUse, out bool overwriteParameterValues) 
    { 
     overwriteParameterValues = true; 
     return true; 
    } 

    public bool OnSharedFamilyFound(Family sharedFamily, bool familyInUse, out FamilySource source, out bool overwriteParameterValues) 
    { 
     source = FamilySource.Family; 
     overwriteParameterValues = true; 
     return true; 
    } 
} 

Проблема заключается в том, что метод PromptForFamilyInstancePlacement позволяет пользователю вставить несколько экземпляров семейства. Я хочу, чтобы пользователь мог вставить только один экземпляр в проект. Я также напишу код, чтобы вернуть вставленный экземпляр (используя событие DocumentChanged, как вы можете видеть), поэтому, возможно, этот обработчик может быть полезен в некотором роде.

ответ

1

Наконец я нашел свое собственное решение (спасибо Jeremy Tammik blog): единственный способ, кажется, отправить комбинацию «Esc» + «Esc» ключ для Windows, в то время как команда выполняет:

Я сделал класс который обрабатывает низкие уровни сообщений:

public class Press 
{ 
    [DllImport("USER32.DLL")] 
    public static extern bool PostMessage(
     IntPtr hWnd, uint msg, uint wParam, uint lParam); 

    [DllImport("user32.dll")] 
    static extern uint MapVirtualKey(
     uint uCode, uint uMapType); 

    enum WH_KEYBOARD_LPARAM : uint 
    { 
     KEYDOWN = 0x00000001, 
     KEYUP = 0xC0000001 
    } 

    enum KEYBOARD_MSG : uint 
    { 
     WM_KEYDOWN = 0x100, 
     WM_KEYUP = 0x101 
    } 

    enum MVK_MAP_TYPE : uint 
    { 
     VKEY_TO_SCANCODE = 0, 
     SCANCODE_TO_VKEY = 1, 
     VKEY_TO_CHAR = 2, 
     SCANCODE_TO_LR_VKEY = 3 
    } 

    /// <summary> 
    /// Post one single keystroke. 
    /// </summary> 
    static void OneKey(IntPtr handle, char letter) 
    { 
     uint scanCode = MapVirtualKey(letter, 
      (uint)MVK_MAP_TYPE.VKEY_TO_SCANCODE); 

     uint keyDownCode = (uint) 
      WH_KEYBOARD_LPARAM.KEYDOWN 
      | (scanCode << 16); 

     uint keyUpCode = (uint) 
      WH_KEYBOARD_LPARAM.KEYUP 
      | (scanCode << 16); 

     PostMessage(handle, 
      (uint)KEYBOARD_MSG.WM_KEYDOWN, 
      letter, keyDownCode); 

     PostMessage(handle, 
      (uint)KEYBOARD_MSG.WM_KEYUP, 
      letter, keyUpCode); 
    } 

    /// <summary> 
    /// Post a sequence of keystrokes. 
    /// </summary> 
    public static void Keys(string command) 
    { 
     IntPtr revitHandle = System.Diagnostics.Process 
      .GetCurrentProcess().MainWindowHandle; 

     foreach (char letter in command) 
     { 
      OneKey(revitHandle, letter); 
     } 
    } 
} 

основной код является следующее:

{ 
... 
_uiApp.Application.DocumentChanged += applicationOnDocumentChanged; 
_uiApp.ActiveUIDocument.PromptForFamilyInstancePlacement(family); 
_uiApp.Application.DocumentChanged -= applicationOnDocumentChanged; 
var el = document.GetElement(_addedElementIds[0]); 
... 
} 


private void applicationOnDocumentChanged(object sender, DocumentChangedEventArgs documentChangedEventArgs) 
{ 
    if (documentChangedEventArgs.GetTransactionNames().Contains("Component")) 
    { 
     _addedElementIds.AddRange(documentChangedEventArgs.GetAddedElementIds()); 
     Press.Keys("" + (char)(int)Keys.Escape + (char)(int)Keys.Escape); 
    } 
} 

Таким образом, только один элемент помещен и Я это Ссылки на сайты e в el переменной.

+0

Кстати, это решение не позволяет установить угол вставки для экземпляров. Они размещаются всегда с углом = 0. Другие способы его достижения? –

+0

Я заметил, что при нажатии на пробел при вставке экземпляра он будет поворачиваться на 90 ° или, соответственно, на ссылку (например, на стену) под углом мыши –

0

Вам нужен пользователь, чтобы иметь возможность выбрать местоположение семейной инстанции?

Если нет, то вы должны использовать метод Document.NewFamilyInstance

Эти сообщения должны помочь выяснить, какие перегрузки использовать:

http://thebuildingcoder.typepad.com/blog/2011/01/newfamilyinstance-overloads.html

http://thebuildingcoder.typepad.com/blog/2013/09/family-instance-placement.html

Если вам нужна пользователю чтобы выбрать местоположение для размещения экземпляра семейства, вы можете потенциально использовать метод Selection.PickPoint, чтобы сначала получить точку местоположения, а затем передать это местоположение в New Метод FamilyInstance.

+0

Мне нужен пользователь, чтобы выбрать точку местоположения, и мне также нужен Revit, чтобы показать предварительный просмотр (под курсором) элемента, который будет вставлен. Решение, которое вы написали, не показывает предварительный просмотр. Должен быть способ остановить выполнение 'PromptForFamilyInstancePlacement' внутри' applicationOnDocumentChanged' (например) –

+0

. Я также заметил вещь: используя «NewFamilyInstance», а затем вызываю свойство Location для вновь вставленного экземпляра, оно всегда возвращает '(0,0,0) LocationPoint'. Используя 'PromptForFamilyInstancePlacement', вставленный экземпляр имеет действительный' LocationPoint'. Также для меня важно это значение («LocationPoint»). –