前言
这篇写选择器,经过前面好些篇的讲解,总算把前置内容都写完了。
我们来回忆下都在哪里提到过…
算了,直接进入正文。
一、Selection 命名空间
选择器位于Autodesk.Revit.UI.Selection
命名空间下,关系到交互嘛,所以在UI
“子”空间下就理所当然了。
所以我们这篇,既是讲整个Selection命名空间下的成员,也会讲Revit选择器的运用。
先来看看都有些什么
Classes 类 | Interfaces 接口 | Enumerations 枚举 |
---|---|---|
Selection | ISelectionFilter | ObjectType |
SelectableInViewFilter | ObjectSnapTypes | |
PickedBox | PickBoxStyle |
这个过滤器,上篇已经讲了嗷,就是过滤指定视图的元素。
再瞧瞧,这个PickBox
也讲过了嗷,看框选聚焦这篇,虽然是给的框选聚焦代码,但它真就只有那么点东西。没有构造函数,只能通过Selection的方法创建;属性就只有min、max这两个。
再看3枚举,
PickBoxStyle
指示怎么选,是接触就算,还是完全包裹才算。ObjectType
指示在选择元素时,哪些能选,就类似可选择集过滤呗,但又不止,好像得放些图看看。ObjectSnapTypes
指示在选择点时,点定位到哪里。比如是起点、终点还是中间啦,这样。
1.1. 选择枚举介绍
上图看效果。
1.1.1. PickBoxStyle(框选枚举)
PickBoxStyle 枚举 | 说明 | 示例 |
---|---|---|
Crossing | 接触就选上 | |
Enclosing | 完全包围才选上 | |
Directional | 从左向右,是包围选择 从右向左,是接触选择 |
1.1.2. ObjectType(选元素枚举)
ObjectType 枚举 | 说明 | 示例 |
---|---|---|
Nothing | 啥也不能选 | |
Element | 啥都能选,返回元素 | |
PointOnElement | 啥都能选,返回射线于模型的交点 | |
Edge | 选边,有Solid 有Edge *才能选 | |
Face | 选面,有Solid 就能选 | |
LinkedElement | 只有链入Revit的才能选 | |
Subelement | 没发现和Element的区别 |
*:什么叫有Solid且有Edge才能选边?讲过了嗷,看这里《获取元素Solid和计算包围盒》。
1.1.3. ObjectSnapTypes(选点枚举)
ObjectSnapTypes 枚举 | 说明 | 示例 |
---|---|---|
None | 啥也不能选 | |
Endpoints | 只能选Edge/Curve 的端点嗷 | |
Points | 哪里都能点,空白处都能点,不知道点的啥东西,或许涉及到屏幕空间坐标转换,不确定。 | |
Midpoints | 选边/线的中间点 | |
Nearest | 选边/线上的最近点 | |
WorkPlaneGrid | 选工作面上的点。好像是面上的网格交点,搞不懂。 | |
Intersections | 射线交点呗 | |
Centers | (圆)弧的中心 | |
Perpendicular | 啥? | |
Tangents | 弧的切线?没选出来 | |
Quadrants | 啥? |
二、Selection 类
Selection
类,不陌生吧,提了好多次了,直接获取
UIDocument uiDoc = commandData.Application.ActiveUIDocument;
Selection selection = uiDoc.Selection;
没啥属性,只有方法,那就直接看看吧。
方法 | 说明 |
---|---|
GetElementIds ,SetElementIds | 获取/设置 选择集,就选中变蓝变透明的效果 |
PickBox x2 | 框个范围,啥效果木有。可用来范围聚焦。 |
PickElementsByRectangle x4 | 框个范围,获取框到的元素。向左接触,向右包含。 |
PickObject x4,PickObjects x4 | 点选模型。 即可点选,又可框选。 |
PickPoint x4 | 选个点 |
没了没了,大体上是没了.jpg
2.1. 选择器的问题
哦~又想起来问题了🙃。
多选时,元素不是按选择顺序返回的,而是按
ElementId
排序
后返回的。
这破玩意儿真令人头疼,我用的2018版本,不清楚更高版本有没有改变。
这可怎么办呢,凉拌。
我也莫得办法。
要么循环单选。
哎,就写到循环单选这会儿,突然想到 似乎 可以借助
AdWindows.dll
来模拟多选完成按钮,以此跳出循环单选。用材质变化,来模拟选中状态。
等我有空研究研究AdWindows.dll再来看看嗷。
三、ISelectionFilter(自定义可选范围)
单纯的选择元素是很难满足需求的,我们更希望的是在有限的、可自定义的范围内,让用户进行选择。
基于这个目标,Revit提供了ISelectionFilter
这个接口,开发者可以通过是实现该接口,来指定哪些元素可选,哪些又不可选。
这里结合上一篇的过滤器,写一个较为通用的可指定过滤器。
直接看代码吧。
不要在ISelectionFilter里进行额外(文档相关、复杂耗时等)操作
[Autodesk.Revit.Attributes.Transaction(Autodesk.Revit.Attributes.TransactionMode.Manual)]
internal class SelectionCommand : IExternalCommand
{
public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements)
{
UIDocument uiDoc = commandData.Application.ActiveUIDocument;
Document doc = uiDoc.Document;
Selection selection = uiDoc.Selection;
// 过滤器,获取Wall
FilteredElementCollector collector = new FilteredElementCollector(doc);
List<ElementId> wallIds = collector.OfCategory(BuiltInCategory.OST_Walls).ToElementIds().ToList();
// ESC
try
{
MySelectionFilter filter = new MySelectionFilter(wallIds);
Reference objRef = selection.PickObject(ObjectType.Element, filter, "Select an element");
Element ele = doc.GetElement(objRef);
TaskDialog.Show("point", ele.Name);
}
catch { }
return Result.Succeeded;
}
}
// 自定义选择过滤器
internal class MySelectionFilter : ISelectionFilter
{
private List<ElementId> _eleIds; // HashSet
public MySelectionFilter(List<ElementId> eleIds)
{
this._eleIds = eleIds;
}
public bool AllowElement(Element elem)
{
if (this._eleIds.Contains(elem.Id)) { return true; }
return false;
}
public bool AllowReference(Reference reference, XYZ position)
{
return true;
}
}
总结
得了得了,这篇到这里了,UI基本完了。
下一个,回到DB,那就看看事务(Transaction
)吧。