I am trying to attach a context menu for unloading an xref when it is selected. (more for curiosity than anything else)
Below is the code I have, which I modified from Kean Walmsley's Post
Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.DatabaseServices Imports Autodesk.AutoCAD.EditorInput Imports Autodesk.AutoCAD.Runtime Imports Autodesk.AutoCAD.Windows Namespace ContextMenuApplication Public Class Commands Implements IExtensionApplication Public Sub Initialize() Implements IExtensionApplication.Initialize XrefMenu.Attach() End Sub Public Sub Terminate() Implements IExtensionApplication.Terminate XrefMenu.Detach() End Sub End Class Public Class XrefMenu Private Shared cme As ContextMenuExtension Public Shared Sub Attach() cme = New ContextMenuExtension() Dim mi As New MenuItem("Unload Xref") AddHandler mi.Click, AddressOf UnloadXrefs cme.MenuItems.Add(mi) Dim rxc As RXClass = Entity.GetClass(GetType(XrefGraphNode)) Application.AddObjectContextMenuExtension(rxc, cme) End Sub Public Shared Sub Detach() Dim rxc As RXClass = Entity.GetClass(GetType(XrefGraphNode)) Application.RemoveObjectContextMenuExtension(rxc, cme) End Sub Private Shared Sub UnloadXrefs(ByVal sender As Object, ByVal e As EventArgs) ''Unload Xrefs End Sub End Class End Namespace
I can't seem to figure out the RXClass required to which I attach the menu. Does anyone have an idea of the RXClass required?
Thanks
Brent
Solved! Go to Solution.
Solved by norman.yuan. Go to Solution.
Hi Brent,
Hopefully some other brilliant person will come back and prove me wrong, but I don't think you're going to be able to pull this one off. An Xref selected in the drawing window would be treated as a BlockReference by AutoCAD. It just has a Flag (in the BlockTableRecord) that says it is Externally Dependant, so I don't see a way to attach a context menu to just Xref's, without having that menu apply to all BlockReferences.
As the other reply points out, you need to specify the RXClass on BlockReference type. Thus, the entity context menu items you created will always available, be it the selected entity is a Blockreference or a Xref.
One solution is to do futher "filtering" on the entity type in the ContextMenuExtension.PopUp event handler. That is, in this event handler, you can test current selected entity (it must be Blockreference, in this case) to if its BlockTablerecord is a Xref/Overlay or not (BlockTableRecord.IsFromExternalReference/IsFromOverlayReference property). and then enable Xref specific menu items accordingly.
I have some code in C#:
using System; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.Runtime; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Windows; namespace ConfigEntContextMenu { public class XrefContextMenu { private ContextMenuExtension _ctMenu = null; private static XrefContextMenu _instance = null; public static XrefContextMenu Instance { get { if (_instance == null) { _instance = new XrefContextMenu(); } return _instance; } } public void AttachMenu() { if (_ctMenu != null) _ctMenu.Dispose(); _ctMenu = new ContextMenuExtension(); MenuItem mi = new MenuItem("Bind Xref"); _ctMenu.MenuItems.Add(mi); mi.Click +=new EventHandler(Bind_Click); mi = new MenuItem("Unload Xref"); _ctMenu.MenuItems.Add(mi); mi.Click += new EventHandler(Unload_Click); mi = new MenuItem("Detach Xref"); _ctMenu.MenuItems.Add(mi); mi.Click += new EventHandler(Detach_Click); _ctMenu.Popup +=new EventHandler(XrefContextMenu_Popup); RXClass rx = RXClass.GetClass(typeof(BlockReference)); Application.AddObjectContextMenuExtension(rx, _ctMenu); } #region private methods private void Bind_Click(object sender, EventArgs e) { Application.ShowAlertDialog("Binding selected XRef"); } private void Unload_Click(object sender, EventArgs e) { Application.ShowAlertDialog("Unloading selected XRef"); } private void Detach_Click(object sender, EventArgs e) { Application.ShowAlertDialog("Detaching selected XRef"); } private void XrefContextMenu_Popup(object sender, EventArgs e) { Document dwg = Application.DocumentManager.MdiActiveDocument; Editor ed = dwg.Editor; bool enable = false; PromptSelectionResult res = ed.SelectImplied(); if (res.Status == PromptStatus.OK) { if (res.Value.Count == 1) { if (IsXref(res.Value.GetObjectIds()[0], dwg)) { enable = true; } } } foreach (MenuItem mi in _ctMenu.MenuItems) { mi.Enabled = enable; } } private bool IsXref(ObjectId id, Document dwg) { bool isX = false; using (Transaction tran = dwg.Database.TransactionManager.StartTransaction()) { BlockReference bref = tran.GetObject(id, OpenMode.ForRead) as BlockReference; if (bref != null) { BlockTableRecord br = (BlockTableRecord)tran.GetObject(bref.BlockTableRecord, OpenMode.ForRead); if (br.IsFromExternalReference || br.IsFromOverlayReference) { isX = true; } } tran.Commit(); } return isX; } #endregion } }
using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.Runtime; using Autodesk.AutoCAD.EditorInput; [assembly: CommandClass(typeof(ConfigEntContextMenu.MyCommands))] [assembly: ExtensionApplication(typeof(ConfigEntContextMenu.MyCommands))] namespace ConfigEntContextMenu { public class MyCommands : IExtensionApplication { #region IExtensionApplication Members public void Initialize() { Document dwg = Application.DocumentManager.MdiActiveDocument; Editor ed = dwg.Editor; try { ed.WriteMessage("\nCreate Xref context menu..."); XrefContextMenu.Instance.AttachMenu(); ed.WriteMessage("...done\n"); } catch(System.Exception ex) { ed.WriteMessage("...failed"); ed.WriteMessage("\nError: {0}\n", ex.Message); } } public void Terminate() { } #endregion #region private methods #endregion } }
Open a drawing with a few blocks inserted and a few Xref attached. You can see the 3 custom context menu items are enabled when right-clicking on Xrefs and disbaled when right-clicking on blocks.
Norman Yuan