第7章、响应MicroStation事件


上一章我们利用DgnPrimitiveTool和DgnElementSetTool捕获到了鼠标的数据键和拒绝键(当然也能捕获到用户的键盘输入),这些都是在Mstn中发生的事件。其实,Mstn中还有更多的事件在发生而且我们可以来捕获它们。下表列出最常见的事件类型以及事件处理函数。

事件类型

事件处理函数

参考设计文件

ReferenceAttachedEvent的方法

卸载参考文件

ReferenceDetachedEvent的方法

打开或关闭设计文件

NewDesignFileEvent(附加到NewDesignFileEvent中)

“另存为”命令

FileSaveAsEvent的方法

激活模型

ModelChangedEvent的方法

跟踪元素的变化

ElementChangedEvent的方法

选择集的变化

SelectionChangedEvent的方法

层的变化

LevelChangeEvent的方法

选择不同视图

SelectedViewChangedEvent的方法

卸载程序

UnloadAnyAppEvent的方法

本章我们以一个例子来进一步使用ILevelChangeEvents和NewDesignFileEventHandler。该例子在一个对话框中显示当前DGN文件中的层,如果您在Mstn的层管理器中新增、删除或改名层后,这个对话框中的层信息会同步修改。另外,当您打开一个新文件时,该对话框中的层信息也会自动更新。下面我们就一步步来构造这个功能。

1.在您的VS中新建一个WinForm,取名叫做LevelChangedForm并给其添加唯一的一个列表框控件。生成的窗体如下图所示:

2.对该窗体进行如下属性设置。注意,我们对列表框的Modifiers属性设置为Public,这样就不必像上一章介绍的那样到LevelChangedForm.Designer.cs文件中直接修改代码了。将列表框的Sorted属性设置为True能使其按字母顺序显示内容。
Form (Name) = LevelChangedForm / FormBorderStyle = FixedDialog / MaximizeBox = False / MinimumBox = False
                             / ShowIcon = False / Size = 288,423 / Text = LevelChangedForm
ListBox (Name) = listBox1 / Location = 5,13  / Modifiers = Public / Size = 272,372 / Sorted = True

3.以代码方式打开LevelChangedForm.cs并修改其内容。最终完整的代码如下。这里需要注意几点:①将LevelChangedForm的基类由Form改成Adapter;②在打开本窗体时会调用到LevelChangedForm_Load方法,在该方法中通过listBox1.Items.Add来将当前DGN文件中的层添加到列表框中;③在窗体的构造函数中,我们添加了两个事件处理器,在窗体被关闭时系统会调用到LevelChangedForm_FormClosed方法,我们在该方法中移除了两个事件处理器。LevelChangedEvent事件会在层发生变化时被激发,NewDesignFileEvent事件会在当前文件发生变化时被激发,在这两个事件处理器中我们都调用了PopulateLevelListListBox内容进行更新。

using Bentley.DgnPlatformNET;
using Bentley.MstnPlatformNET;
using Bentley.MstnPlatformNET.WinForms;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static Bentley.MstnPlatformNET.AddIn;

namespace csAddins
{
    public partial class LevelChangedForm : //Form
        Adapter
    {
        public LevelChangedForm()
        {
            InitializeComponent();
            //添加层变化以及打开新文件会触发的事件处理函数
            MyAddin.Addin.LevelChangeEvent += LevelChangeEventHandler;
            MyAddin.Addin.NewDesignFileEvent += NewDesignFileEventHandler;
        }

        //界面加载时,获取当前文件中所有的层名并显示到listbox中
        private void LevelChangedForm_Load(object sender, EventArgs e)
        {
            FileLevelCache fileLevelCache=Session.Instance.GetActiveDgnFile().GetLevelCache();
            LevelHandleCollection levelHandleCol = fileLevelCache.GetHandles();
            foreach(LevelHandle levelHandle in levelHandleCol)
            {
                listBox1.Items.Add(levelHandle.Name);
            }
        }

        //界面关闭时要卸载掉我们之前添加的事件处理函数
        private void LevelChangedForm_FormClosed(object sender, FormClosedEventArgs e)
        {
            MyAddin.Addin.LevelChangeEvent -= LevelChangeEventHandler; 
            MyAddin.Addin.NewDesignFileEvent -= NewDesignFileEventHandler;
        }

        //根据参数eventArgsIn.Change判断层发生了何种变化,进而决定是否更新界面中的层名
        private void LevelChangeEventHandler(AddIn senderIn, LevelChangeEventArgs eventArgsIn)
        {
            if (eventArgsIn.Change == LevelChangeEventArgs.ChangeType.Create ||
                eventArgsIn.Change == LevelChangeEventArgs.ChangeType.Delete ||
                eventArgsIn.Change == LevelChangeEventArgs.ChangeType.TableRewrite ||
                eventArgsIn.Change == LevelChangeEventArgs.ChangeType.ChangeName)
                PopulateLevelList();
        }

        //打开新文件时更新界面上的层名
        private void NewDesignFileEventHandler(AddIn sender, NewDesignFileEventArgs eventArgs)
        {
            if (AddIn.NewDesignFileEventArgs.When.AfterDesignFileOpen == eventArgs.WhenCode)
                PopulateLevelList();
        }

        private void PopulateLevelList()
        {
            listBox1.Items.Clear();
            LevelHandleCollection levelCollection = Session.Instance.GetActiveDgnFile().GetLevelCache().GetHandles();
            foreach (LevelHandle myLvl in levelCollection)
                listBox1.Items.Add(myLvl.Name);
        }
    }
}

4.打开commands.xml文件,新增命令csAddins DemoForm LevelChanged并指定其处理函数为csAddins.DemoForm.LevelChanged。如果您对XML格式的命令表文件还不熟悉,请参考第四章的相关主题。

5.打开DemoForm.cs,翻到代码尾部增加命令处理函数LevelChanged如下。这段代码以单实例(Singleton)模式打开LevelChangedForm,即保证同时只能有一个该窗体被打开。

private static LevelChangedForm myLevelForm = null;

        public static void LevelChanged(string unparsed)
        {
            if (null == myLevelForm || myLevelForm.IsDisposed)
            {
                myLevelForm = new LevelChangedForm();
                myLevelForm.AttachAsTopLevelForm(MyAddin.Addin, false);
                myLevelForm.Show(); 
            }
            else
                myLevelForm.Activate();
        }

6.完成了代码的编写后就让我们来实际测试一下。首先在VS中重新生成csAddins。然后启动Mstn,键入mdl load csAddins装载csAddins,再键入csaddins demoform levelchanged打开LevelChanged窗体。打开Mstn的层管理器,如下图所示。当您在Level Manager窗口中增加、删除层或对某层改名后,我们的LevelChanged窗体中的显示也会立即更新。您还可以通过打开另一个DGN来进一步测试,您会发现LevelChanged窗体中的内容会随着新文件的打开而改变。

下面是整个项目的源代码,供您参考。

communities.bentley.com/.../7217.csAddins.7z