1

初めての Revit プラグインを作成しようとしています。

Revit 2014 を使用していますが、ファイルからロードしたファミリの単一のインスタンスを配置したいと考えています。私は実際にこのコードを使用しています:

[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ではユーザーがファミリの複数のインスタンスを挿入できることです。ユーザーがプロジェクトに挿入できるインスタンスは 1 つだけです。挿入されたインスタンスを戻すためのコードも記述します (DocumentChangedご覧のとおり、イベントを使用)。

4

2 に答える 2

1

最後に、私は独自の解決策を見つけました ( Jeremy Tammik ブログのおかげです):コマンドの実行中に「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);
    }
}

このようにして、要素が 1 つだけ配置され、el変数への参照ができました。

于 2014-01-13T11:09:16.057 に答える