CAD二次开发 学习笔记(4)
CAD二次开发 学习笔记(4)
事件处理程序的原则
事件只是简单地提供了关于 AutoCAD 的状态或发生在 AutoCAD 中的活动的信息,记住这一点非常重要的。 尽管可以编写事件处理程序来响应那些事件,但触发事件处理程序的操作中间是有个 AutoCAD 在那儿的。 因此,如果想让事件处理程序与 AutoCAD 及数据库一起使用时提供安全可靠的操作,必须对事件处理程序能做什么不能做什么有所限制。
? 原则 1: 不要依赖于事件的顺序。
编写事件处理程序时, 不要依赖于你所认为的事件发生的确切顺序序列。 例如,如果你运行 OPEN 命令, CommandWillStart 事件、 DocumentCreateStarted 事件、DocumentCreated 事件和 CommandEnded 事件都会被触发。 然而, 这些事件可能不会每次都以确切的顺序发生。 你唯一可以依赖的是成对儿发生的那两个事件:开始事件和结束事件。
? 原则 2:不要依赖于操作的顺序。
如果你删除了对象 1,然后又删除了对象 2,不要依赖一个事实,即您将先收到对象1 的 ObjectErased 事件,然后收到对象 2 的 ObjectErased 事件。 你可能会先收到对象 2 的 ObjectErased 事件。
? 原则 3: 不要从事件处理程序内尝试任何交互功能。
试图从事件处理程序内执行交互功能会引起严重问题,因为事件被触发时 AutoCAD可能仍在处理命令。 因此, 应该牢记避免从事件处理程序中执行下列操作: 在命令提示行请求输入、 请求选择对象以及使用 SendStringToExecute()方法等。
? 原则 4:不要从事件处理程序内启动对话框。
一般认为对话框是一种交互功能,会干扰到 AutoCAD 的当前操作,而消息框和警告框不是交互功能,可以放心使用; 不过,在下列事件的处理程序里发出消息框可能会导致意想不到的结果序列: EnterModal、 LeaveModal、 DocumentActivated、DocumentToBeDeactivated 等。
? 原则 5:可以向数据库中的任何对象写入数据,但应避免修改引发事件的那个对象。
很显然,引发事件的那个对象已经打开并且还处在当前的操作过程中。因此,应避免从该对象的事件处理程序修改这个对象。不过,可以放心地从触发事件的对象读取信息。
? 原则 6: 不要从事件处理程序执行可能会触发相同事件的任何操作。
如果在事件处理程序中执行触发同一事件的相同动作,就会进入一个无限循环(死循环)。例如,永远不要试图在 ObjectOpenedForModify 事件的处理程序中打开一个对象,否则 AutoCAD 就会不停地打开对象、打开对象……
? 原则 7: 当 AutoCAD 显示一个模式对话框时没有事件被触发。
对象事件
Polyline polyline = null;
///
/// 创建多段线,并添加修改事件的处理程序
///
[CommandMethod("AddPolylineEvent")]
public void AddPolylineEvent()
{
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr=db.TransactionManager.StartTransaction())
{
BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
BlockTableRecord btr = tr.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite) as BlockTableRecord;
polyline = new Polyline();
Random r = new Random();
for (int i = 0; i < 5; i++)
{
polyline.AddVertexAt(i,new Point2d(r.Next(0,500), r.Next(0, 200)),0,r.Next(0,5), r.Next(0, 5));
}
polyline.Closed = true;
btr.AppendEntity(polyline);
tr.AddNewlyCreatedDBObject(polyline,true);
polyline.Modified += PolylineModified;
tr.Commit();
}
}
///
/// 移除事件处理程序
///
[CommandMethod("RemovePolylineEvent")]
public void RemovePolylineEvent()
{
if (polyline == null) return;
Database db = HostApplicationServices.WorkingDatabase;
using (Transaction tr=db.TransactionManager.StartTransaction())
{
polyline = tr.GetObject(polyline.ObjectId, OpenMode.ForRead) as Polyline;
if (polyline.IsWriteEnabled == false) polyline.UpgradeOpen();
polyline.Modified -= PolylineModified;
polyline = null;
}
}
private void PolylineModified(object sender, EventArgs e)
{
Application .ShowAlertDialog($"多段线的面积是{polyline.Area}");
}
运行结果
文档集合事件
#region 文档集DocumentCollection事件的测试
///
/// 添加事件处理程序到文档激活事件
///
[CommandMethod("AddDocCollEvent")]
public void AddDocCollEvent()
{
Application.DocumentManager.DocumentActivated += DocActivatedHandler;
}
///
/// 从文档激活事件移除事件处理程序
///
[CommandMethod("RemoveDocCollEvent")]
public void RemoveDocCollEvent()
{
Application.DocumentManager.DocumentActivated -= DocActivatedHandler;
}
///
/// 文档激活事件的处理程序
///
///
///
private void DocActivatedHandler(object sender, DocumentCollectionEventArgs e)
{
Application.ShowAlertDialog($"{e.Document.Name}被激活了!");
}
#endregion
运行结果
文档事件测试
#region 文档Document事件测试
///
/// 添加事件处理程序到文档关闭事件
///
[CommandMethod("AddDocEvent")]
public void AddDocEvent()
{
Application.DocumentManager.MdiActiveDocument.BeginDocumentClose += BeginDocCloseHandler;
}
///
/// 从文档关闭事件移除事件处理程序
///
[CommandMethod("RemoveDocEvent")]
public void RemoveDocEvent()
{
Application.DocumentManager.MdiActiveDocument.BeginDocumentClose -= BeginDocCloseHandler;
}
///
/// 事件处理程序
///
///
///
private void BeginDocCloseHandler(object sender, DocumentBeginCloseEventArgs e)
{
string[] m = new string[] { $"文档即将关闭。 \n确认继续?", "关闭文档" };
if (MessageBox.Show(m[0], m[1], MessageBoxButtons.YesNo) == DialogResult.No)
e.Veto();
}
#endregion
运行结果
CAD事件测试-更改系统变量,并触发事件(弹出一个警告对话框,并显示更改内容)
///
/// 将事件处理程序注册(添加)到事件
///
[CommandMethod("AddAppEvent")]
public void AddAppEvent()
{
Application.SystemVariableChanged += SystemVariableChangedHandler;
}
///
/// 取消事件处理程序的注册(移除)
///
[CommandMethod("RemoveAppEvent")]
public void RemoveAppEvent()
{
Application.SystemVariableChanged -= SystemVariableChangedHandler;
}
///
/// 定义事件处理程序
///
///
///
private void SystemVariableChangedHandler(object sender, SystemVariableChangedEventArgs e)
{
Application.ShowAlertDialog($"\n改变了系统变量:{e.Name}\n改变后的值为:{Application.GetSystemVariable(e.Name)}");
}
运行结果
通过选择一个dwg文件,来启动CAD,并与CAD相关联
///
/// 通过选择dwg文件,启动CAD,以便与CAD进行关联
///
private void StartCAD()
{
try
{
app = System.Runtime.InteropServices.Marshal.GetActiveObject("AutoCAD.Applicaton") as AcadApplication;
doc = app.ActiveDocument;
}
catch (Exception)
{
OpenFileDialog dialog = new OpenFileDialog();
dialog.Filter = "CAD文件(*.dwg)|*.dwg|CAD图形文件(*.dxf)|*.dxf";
dialog.ShowDialog();
dialog.Title = "打开CAD文件";
string path = dialog.FileName;
if (path == "")
{
MessageBox.Show("选择文件无效!", "文件无效!");
Application.Exit();
}
app = new AcadApplication();
if (File.Exists(path))
doc = app.Documents.Open(path, null, null);
}
app.Visible = true;
Microsoft.VisualBasic.Interaction.AppActivate(app.Caption);
}
通过WinForm程序,获取选择集对象,并显示直线对象的坐标信息到WinForm窗体控件
AcadApplication app;
AcadDocument doc;
///
/// 通过手动选择获取选择集,从而获取直线坐标
///
///
///
private void button_GetLineCoords_Click(object sender, EventArgs e)
{
Microsoft.VisualBasic.Interaction.AppActivate(app.Caption);
AcadSelectionSet ss = doc.SelectionSets.Add("NewSelectionSet001");
Int16[] filterType = new Int16[] { 0 };
object[] filterData = new object[] { "*" };
ss.SelectOnScreen(filterType, filterData);
if (ss == null) return;
int count = 1;
foreach (AcadObject item in ss)
{
if (item.ObjectName == "AcDbLine")
{
AcadLine line = (AcadLine)item;
listBox1.Items.Add($"第{count}条直线坐标");
listBox1.Items.Add($"起点坐标X:{line.StartPoint[0]},Y:{line.StartPoint[1]},Z:{line.StartPoint[2]}");
listBox1.Items.Add($"终点坐标X:{line.EndPoint[0]},Y:{line.EndPoint[1]},Z:{line.EndPoint[2]}");
count++;
}
}
listBox1.Items.Add($"共选择{ss.Count}个对象,其中直线{count - 1}条");
doc.SelectionSets.Item("NewSelectionSet001").Delete();
Microsoft.VisualBasic.Interaction.AppActivate(this.Text);
}
运行结果