AutoCAD.Net开发问题之:层表事件的响应(续)

之前在 AutoCAD.Net开发问题之:层表事件的响应 中,没找到直接响应层表的事件,就用了 Dababase 的 Object 相关事件来替代。在测试过程中发现监听图层变化的目的倒是达到了,但会严重影响编辑操作:绘图时,任何一个简单的操作都会触发大量事件,每次事件都涉及拆箱处理,一想到每个简单操作后台都如此"沉重",强迫症不能忍。

几乎用度娘找遍了所有相关关键词,未果,最后还是谷歌给力,网上找到一篇完美解决方案:
Finding out about changes to AutoCAD layers via the Bindable Object Layer using .NET
其实也没啥可说的,关键代码就一行:

Application.UIBindings.Collections.Layers

应该是通过系统的数据绑定获取相关信息,这东西知道就很简单,直接上代码:

	using Autodesk.AutoCAD.ApplicationServices;
	using Autodesk.AutoCAD.EditorInput;
	using Autodesk.AutoCAD.Runtime;
	using Autodesk.AutoCAD.Windows.Data;
	using System.Collections.Specialized;
	using System.Collections.Generic;
	using System.ComponentModel;
	
	public class BolInfo
    {
        private static List<string> _layerNames = null;

        [CommandMethod("LAYMODS")]
        public static void GetNotifiedOnLayerChange()
        {
            // Get our layer list and extract the initial layer names
            var layers = Application.UIBindings.Collections.Layers;
            UpdateStoredLayerNames();

            // Attach event handlers to the layer list...
            // Find out when items are added or removed from the collection
            layers.CollectionChanged += (s, e) =>
            {
                Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
                ed.WriteMessage("\nCollection changed: {0}", e.Action);
                if (e.Action == NotifyCollectionChangedAction.Add && e.NewStartingIndex == -1)
                {
                    // What happens for commands that create >1 layers?
                    var newLays = Application.UIBindings.Collections.Layers;
                    ed.WriteMessage("\nNew item: \"{0}\"", GetItemValue(newLays[newLays.Count - 1]));
                }
                else if (e.Action == NotifyCollectionChangedAction.Remove)
                {
                    ed.WriteMessage("\nRemoved item: \"{0}\"", _layerNames[e.OldStartingIndex]);
                }

                // As we can't access data in e.NewItems or e.OldItems
                // (they contain NewDataItem objects - a class that isn't exposed) get the collection again and list it
                ed.WriteMessage("\nUpdated collection: ");

                foreach (var item in Application.UIBindings.Collections.Layers)
                {
                    ed.WriteMessage(" \"{0}\"", GetItemValue(item));
                }

                UpdateStoredLayerNames();
            };

            // Find out when items have been changed in the collection (although not what specifically has changed)
            layers.ItemsChanged += (s, e) =>
            {
                Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
                ed.WriteMessage("\nItem(s) changed.");
                UpdateStoredLayerNames();
            };

            // Find out when properties of the collection (typically the Count, for instance) have changed
            layers.PropertyChanged += (s, e) =>
            {
                Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
                ed.WriteMessage("\nCollection property changed: {0}", e.PropertyName);
            };
        }

        // Store a cache of the layer names
        private static void UpdateStoredLayerNames()
        {
            var layers = Application.UIBindings.Collections.Layers;
            _layerNames = new List<string>(layers.Count);
            foreach (var layer in layers)
            {
                _layerNames.Add(GetItemValue(layer));
            }
        }

        // Extract the name of an item from the item descriptor
        private static string GetItemValue(ICustomTypeDescriptor item)
        {
            return (string) item.GetProperties()["Name"].GetValue(item);
        }
    }

在此对作者 Kean Walmsley 表示感谢!相信不少同学看过他的文章,也有不少大大翻译整理,感谢感谢,努力迈进。


20191126更新:

好吧,这个方法也并不完美,Kean 提到的 ItemsChanged 不能捕捉具体哪个图层发生变化算是问题之一,不过不算主要问题。

主要问题是通知滞后性,UIBindings 的方式对常规操作完全可以胜任,但对于高频操作可能出问题。通过代码添加多个图层暂且不提,测试在系统自带的图层管理器连续新建图层,会发现间或有事件没被捕捉到。发现这个问题后又回去看原文,看有没解决办法,结果发现 Kean 的测试也有同样问题( ╯□╰ )。

下面是 Kean 测试的效果,中间有个小问题(不晓得ta发现没)

Command: LAYMODS
Command: LAYER
Command:
Command:
Collection changed: Add
New item: “Layer1”
Updated collection: “0” “Layer1”
Collection property changed: Count
Command:
Collection changed: Add
New item: “Layer2”
Updated collection: “0” “Layer1” “Layer2”
Collection property changed: Count
Command:
Collection changed: Add
New item: “Layer3”
Updated collection: “0” “Layer1” “Layer2” “Layer3”
Collection property changed: Count
Command:
Collection changed: Add
New item: “Layer4”
Updated collection: “0” “Layer1” “Layer2” “Layer3” “Layer4”
Collection property changed: Count
Command:
Collection changed: Add
New item: “Layer5”
Updated collection: “0” “Layer1” “Layer2” “Layer3” “Layer4” “Layer5”
Collection property changed: Count
Command:
Command:
Collection changed: Add
New item: “Layer7”
Updated collection: “0” “Layer1” “Layer2” “Layer3” “Layer4” “Layer5” “Layer6” “Layer7”
Collection property changed: Count
Command:
Collection changed: Add
New item: “Layer8”
Updated collection: “0” “Layer1” “Layer2” “Layer3” “Layer4” “Layer5” “Layer6” “Layer7” “Layer8”
Collection property changed: Count

细看上面 Layer5 到 Layer7,中间缺了个 Layer6 ,应该就是连续新建图层,事件通知来不及造成的,使用时候要注意。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值