前言
这篇写选择器,经过前面好些篇的讲解,总算把前置内容都写完了。
 我们来回忆下都在哪里提到过…
 算了,直接进入正文。
一、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 | 获取/设置 选择集,就选中变蓝变透明的效果 | 
PickBoxx2 | 框个范围,啥效果木有。可用来范围聚焦。 | 
PickElementsByRectanglex4 | 框个范围,获取框到的元素。向左接触,向右包含。 | 
PickObjectx4,PickObjectsx4 | 点选模型。 即可点选,又可框选。  | 
PickPointx4 | 选个点 | 
没了没了,大体上是没了.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)吧。


























