使用C#插件将族的单个实例放置到Revit项目中
我正在尝试创建我的第一个Revit插件 我使用的是Revit 2014,我想要的是放置从文件加载的族的单个实例。我实际使用的代码是:使用C#插件将族的单个实例放置到Revit项目中,c#,.net,revit-api,C#,.net,Revit Api,我正在尝试创建我的第一个Revit插件 我使用的是Revit 2014,我想要的是放置从文件加载的族的单个实例。我实际使用的代码是: [TransactionAttribute(TransactionMode.Manual)] [RegenerationAttribute(RegenerationOption.Manual)] public class InsertFamily : IExternalCommand { readonly List<ElementId> _ad
[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;
}
}
[TransactionAttribute(TransactionMode.Manual)]
[再生属性(再生选项.手动)]
公共类InsertFamily:IExternalCommand
{
只读列表_addedElementIds=新列表();
公开结果执行(
外部命令数据命令数据,
参考字符串消息,
元素集元素)
{
UIApplication uiApp=commandData.Application;
Document Document=uiApp.ActiveUIDocument.Document;
FamilySymbol family=null;
bool good=false;
使用(var trans=新交易(文档“插入系列”))
{
trans.Start();
good=document.LoadFamilySymbol(@“我的文件路径.rfa”,“我的类型”,new FamilyLadingGoverWriteOption(),out family);
trans.Commit();
}
if(良好和家庭!=null)
{
_addedElementIds.Clear();
uiApp.Application.DocumentChanged+=应用程序文件更改;
uiApp.ActiveUIDocument.PromptForFamilyInstancePlacement(家庭);
uiApp.Application.DocumentChanged-=应用程序内文档已更改;
}
返回结果。成功;
}
私有void应用程序内文档已更改(对象发送方,DocumentChangedEventArgs DocumentChangedEventArgs)
{
_addedElementIds.AddRange(documentChangedEventArgs.GetAddedElementIds());
}
}
类FamilyLadingGoverWrite选项:IFamilyLoadOptions
{
公共bool-OnFamilyFound(bool-familyInUse、out-bool-overwriteparametervalue)
{
overwriteParameterValues=true;
返回true;
}
公共bool-OnSharedFamilyFound(家庭共享家庭、bool-FamilyUse、out-FamilySource源、out-bool覆盖参数值)
{
source=FamilySource.Family;
overwriteParameterValues=true;
返回true;
}
}
问题在于,方法
PromptForFamilyInstancePlacement
允许用户插入该族的多个实例。我希望用户只能在项目中插入一个实例。我还编写了返回插入实例的代码(如您所见,使用DocumentChanged
事件),因此该处理程序在某些方面可能有用。您是否需要用户能够选择族实例的位置
如果没有,则应使用Document.NewFamilyInstance方法
这些帖子应该有助于澄清使用哪种重载:
如果确实需要用户选择放置族实例的位置,则可以使用Selection.PickPoint方法首先获取位置点,然后将该位置传递给NewFamilyInstance方法。是否需要用户能够选择族实例的位置 如果没有,则应使用Document.NewFamilyInstance方法 这些帖子应该有助于澄清使用哪种重载:
如果确实需要用户选择放置族实例的位置,则可以使用Selection.PickPoint方法首先获取位置点,然后将该位置传递给NewFamilyInstance方法。最后我找到了自己的解决方案(感谢):唯一的方法似乎是发送“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);
}
}
}
通过这种方式,只放置了一个元素,我将其引用到
el
变量中。最终我找到了自己的解决方案(感谢):执行命令时,唯一的方法似乎是将“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);
}
}
}
通过这种方式,只放置一个图元,并将其引用到
el
变量中。我需要用户选择位置点,还需要Revit显示将插入的图元的预览(在光标下)。您编写的解决方案没有显示预览..应该有一种方法可以停止应用程序内的PromptForFamilyInstancePlacement
执行,并更改了(例如)我还注意到一件事:使用NewFamilyInstance
,然后调用新插入实例的属性位置,它总是返回一个(0,0,0)位置点
。使用promptforfamilyinstanceplace
插入的实例具有有效的LocationPoint
。此外,此值(LocationPoint
)对我来说很重要,我需要用户选择位置点,我还需要Revit显示将插入的图元的预览(在光标下)。您编写的解决方案没有显示预览..应该有一种方法可以停止应用程序内的PromptForFamilyInstancePlacement
执行,并更改了(例如)我还注意到一件事:使用NewFamilyInstance
,然后调用新插入实例的属性位置,它总是返回一个(0,0,0)位置点
。使用promptforfamilyinstanceplace
插入的实例具有有效的LocationPoint
。此外,此值(LocationPoint
)对我来说是有效的,这一点很重要。顺便说一下,此解决方案不允许为实例设置插入角度。它们始终以角度=0的方式放置。还有其他方法吗?我注意到,在插入实例时按空格键,它将旋转90°,或相应地旋转到鼠标角度下的参考(如墙),因为此解决方案不允许为实例设置插入角度。它们始终以角度=0的方式放置。还有别的方法吗?我注意到了