• cad.net 操作cui和cuix含工具条


    版本说明

    本文测试为Acad2008(Cui)和Acad2021(Cuix)的案例,应该能够涉及所有高低版本的操作.
    Cui是个xml,Cuix是个压缩包...知道好像没什么好处,还是应该调用管理器操作而不是序列化操作.
    关于宏的说明,看这个桌子的链接

    特别的bug

    public static class CuiStatic
    {
      #if NET35
        //为了让Acad2008配合高版本的API,所以写了个拓展方法给它
        public static bool RemovePartialMenu(this CustomizationSection cs, string fileName, string menuGroupName)
        {
            return cs.RemovePartialMenu(fileName);//卸载局部cui
        }
      #endif
    }
    

    然后 cs.RemovePartialMenu 这个万恶之源,令我在测试Acad2021移除未融入的cuix的时候是失效的,为什么失效呢?

    在我百思不得其解的时候,执行了一次"_.CuiUnLoad"自带的卸载命令,它会将cuix某些错误修复了,

    然后再执行 cs.RemovePartialMenu 是成功的了.

    修改主cui和cuix

    using Autodesk.AutoCAD.Customization;
    using Autodesk.AutoCAD.Runtime;
    using Autodesk.AutoCAD.DatabaseServices;
    using Autodesk.AutoCAD.ApplicationServices;
    using Autodesk.AutoCAD.EditorInput;
    //需要引用 AcCui.dll
    
    namespace JoinBox.Menu
    {
        // 修改mainCui文件,可以考虑更换为修改局部cui替代
        // 参考来自 https://adndevblog.typepad.com/autocad/2012/12/customizing-double-click-on-block-reference.html
        public partial class Cmd
        {
            [CommandMethod("ChangeMacroCUI")]
            public void ChangeMacroCUI()
            {
                var cs = Cui.CuiMain(out string expand);
                //遍历所有双击动作
                DoubleClickAction ad = null;
                foreach (DoubleClickAction dca in cs.MenuGroup.DoubleClickActions)
                {
                    if (dca.Name == "块" || dca.Name == "Block")
                    {
                        ad = dca;
                        var ma = ad.DoubleClickCmd.MenuMacroReference.macro;
    #if true
                        ma.Command = "$M =$(if,$(and,$(>,$(getvar,blockeditlock),0)),^C^C_properties,^C^C_bedit)"; //原始的
    #else
                        ma.Command = $"^C^C_{Cmd_MyBEdit}";//新创建的命令
    #endif
                    }
                    if (dca.Name == "属性块")
                    {
                        ad = dca;
                        var ma = ad.DoubleClickCmd.MenuMacroReference.macro;
    #if true
                        ma.Command = "^C^C_eattedit"; //原始的
    #else
                        ma.Command = $"^C^C_{Cmd_MyBEdit}";//新创建的命令
    #endif
                    }
                }
                if (cs.IsModified)
                {
                    cs.SaveAs(cs.CUIFileName);//保存覆盖掉主cui文件
                    CuiStatic.CuiAcedReloadMenus();
                }
            }
    
            const string Cmd_MyBEdit = "MyBEdit";
            [CommandMethod(Cmd_MyBEdit, CommandFlags.UsePickSet)]
            public void MyBeditCommand()
            {
                var doc = Application.DocumentManager.MdiActiveDocument;
                var ed = doc.Editor;
                var db = doc.Database;
                string regAppName = "MyApp";
    
                ed.WriteMessage("
     aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
                return;
    
                var result = ed.GetSelection();
                if (result.Status != PromptStatus.OK)
                {
                    return;
                }
                var ss = result.Value;
                foreach (SelectedObject so in ss)
                {
                    bool isMyBlockRef = false;
                    db.Action(tr =>
                    {
                        var ent = so.ObjectId.ToEntity(tr);
                        // 让我们检查XDATA以识别我们是否需要显示我们的对话框
                        if (ent.GetXDataForApplication(regAppName) != null)
                        {
                            isMyBlockRef = true;
                        }
                    });
    
                    if (isMyBlockRef)
                    {
                        Application.ShowAlertDialog("定制行动,如显示我们的表格。");
                    }
                    else
                    {
                        // 让Auto CAD进行块编辑。
                        ObjectId[] ids = ss.GetObjectIds();
                        ed.SetImpliedSelection(ids);
                        doc.SendStringToExecute("_BEDIT ", false, false, false);
                    }
                }
            }
        }
    }
    

    修改局部Cui和Cuix

    大多数时候不需要修改主Cui而是用局部Cui,因为局部Cui会替代主Cui的动作.

    using System.IO;
    using Autodesk.AutoCAD.ApplicationServices;
    using Autodesk.AutoCAD.Customization;
    using Autodesk.AutoCAD.EditorInput;
    using Autodesk.AutoCAD.Runtime;
    
    namespace JoinBox.Menu
    {
        // 修改局部cui文件
        // 参考来自: https://through-the-interface.typepad.com/through_the_interface/2007/05/creating_a_part.html
        public partial class Cmd
        {
            /// <summary>
            /// 建立CUI菜单
            /// </summary>
            [CommandMethod("BuildMenuCUI")]
            public void BuildMenuCUI()
            {
                Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
                var pcfs = Cui.CuiMain(out string expand).PartialCuiFiles;//局部cui
    
                string myCuiName = "Kean";
                string myCuiFile = AutoGo.ConfigPath + myCuiName + expand;
                string msg = $"
    自定义CUI文件: "{myCuiFile}" ";
    
                if (pcfs.Contains(myCuiFile))
                {
                    ed.WriteMessage(msg + "已经加载;");
                    ed.WriteMessage("
    执行卸载");
                    Cui.UnLoad(myCuiName);
                    ed.WriteMessage("
    卸载成功");
                    return;
                }
    
                if (File.Exists(myCuiFile))
                {
                    ed.WriteMessage(msg + "存在,");
                }
                else
                {
                    ed.WriteMessage(msg + "不存在建立它,");
                    var pcs = CuiCreate(myCuiName, "Attblockref");//属性块
                    pcs.SaveAs(myCuiFile);   //保存文件可能因为c盘权限而失败,更换到其他盘
                }
    
                ed.WriteMessage("执行加载
    ");
                Cui.Load(myCuiFile);
                CuiStatic.CuiAcedReloadMenus();
            }
    
            /// <summary>
            /// 创建CUI菜单双击
            /// </summary>
            /// <param name="cuiName">cui菜单的名称</param>
            /// <param name="dxfName">限定双击对象的类型,例如"Circle" "Attblockref"</param>
            /// <returns></returns>
            private static CustomizationSection CuiCreate(string cuiName, string dxfName)
            {
                // 为我们的部分菜单创建自定义部分
                var pcs = new CustomizationSection
                {
                    MenuGroupName = cuiName
                };
    
                string doubleClick = "DoubleClick";
                //cui双击事件名称...这里也是命令定义的名称,需要用这个名称去动态编译一个命令出来...
                string actionName = $"{doubleClick}ActionName_{cuiName}";
    
                //创建双击动作...局部的定义会覆盖掉主cui的定义,覆盖顺序未知
                var dca = new DoubleClickAction(pcs.MenuGroup, actionName, -1)
                {
                    Description = "双击自定义",
                    ElementID = "EID_" + actionName,
                    DxfName = dxfName
                };
    
                var macGroup = new MacroGroup($"MacroGroup_{cuiName}", pcs.MenuGroup);
                //actionName是执行的命令,你把他当成命令的唯一身份证号码
                var createMenuMacro = macGroup.CreateMenuMacro(actionName, $"^C^C_{actionName}", $"ID_{dxfName}_{doubleClick}_{cuiName}");
    
                var cmd = new DoubleClickCmd(dca)
                {
                    MacroID = createMenuMacro.ElementID
                };
                dca.DoubleClickCmd = cmd;
                return pcs;
            }
    
            //这里还没有完成动态编译.......就将就一下
            const string Cmd_double = "DoubleClickActionName_Kean";//CuiCreate提供的...最好修改成动态编译
            [CommandMethod(Cmd_double)]
            public void DoubleClickActionName_Kean()
            {
                Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
                ed.WriteMessage("
    双击属性块执行了我耶");
            }
        }
    }
    

    Cui类

    using System;
    using System.Text;
    using System.IO;
    using Autodesk.AutoCAD.Customization;
    using Autodesk.AutoCAD.ApplicationServices;
    using Acap = Autodesk.AutoCAD.ApplicationServices.Application;
    
    namespace JoinBox.Menu
    {
        public class Cui
        {
            /// <summary>
            /// 打开主CUI文件
            /// </summary>
            /// <param name="expand">拓展名</param>
            /// <returns></returns>
            public static CustomizationSection CuiMain(out string expand)
            {
                expand = "";
                //打开主CUI文件,可以考虑局部cui文件
                string old = (string)Acap.GetSystemVariable("MENUNAME");
                var mainCuiFile = old;
                if (mainCuiFile == null)
                {
                    throw new ArgumentNullException(nameof(CuiMain));
                }
                if (File.Exists(mainCuiFile + ".cuix"))
                {
                    mainCuiFile += ".cuix";//高版本
                    expand = ".cuix";
                }
                else if (File.Exists(mainCuiFile + ".cui"))
                {
                    mainCuiFile += ".cui";//低版本08
                    expand = ".cui";
                }
                if (mainCuiFile == old)
                {
                    throw new ArgumentNullException("没有找到对应的cui文件:" + nameof(CuiMain));
                }
                //反序列化这个文件打开
                return new CustomizationSection(mainCuiFile);
            }
    
            /// <summary>
            /// 加载CUI文件
            /// </summary>
            /// <param name="cuiFile">cui文件路径</param>
            public static void Load(string cuiFile)
            {
                SendCmd("_.CuiLoad", new string[] { cuiFile });
                //var cs = CuiMain(out string expand);
                //cs.AddPartialMenu()//加载局部cui,加载类的
            }
    
            /// <summary>
            /// 卸载CUI文件
            /// </summary>
            /// <param name="cuiMenuGroupName">组名</param>
            public static void UnLoad(string cuiMenuGroupName)
            {
                // AccordingCadLispSendCmd("_.CuiUnLoad", new string[] { cuiMenuGroupName });
    
                var cs = CuiMain(out string expand);
                UnLoad(cs, cuiMenuGroupName);
            }
    
            /// <summary>
            /// 卸载局部cui
            /// </summary>
            /// <param name="cs">MainCui</param>
            /// <param name="removeCuiFile">指定移除的文件</param>
            /// <param name="removeBadFile">移除坏掉的cui</param>
            static void UnLoad(CustomizationSection cs, string removeCuiFile, bool removeBadFile = true)
            {
                var pcfs = cs.PartialCuiFiles;//局部cui
    
                //移除坏掉的cui(删除路径的文件之后显示未融入的)
                if (removeBadFile)
                {
                    for (int i = 0; i < pcfs.Count; i++)
                    {
                        var fileName = pcfs[i];
                        if (!File.Exists(fileName))
                        {
                            RemovePartialMenu(cs, pcfs, fileName);
                            i--;
                        }
                    }
                }
    
                //移除指定名称的局部cui文件
                for (int i = 0; i < pcfs.Count; i++)
                {
                    var fileName = pcfs[i];
                    if (removeCuiFile.ToUpper() == GetFileName(fileName).ToUpper())
                    {
                        RemovePartialMenu(cs, pcfs, fileName);
                        i--;
                    }
                }
    
                if (cs.IsModified)
                {
                    cs.Save();
                }
            }
    
            /// <summary>
            /// 移除局部cui
            /// </summary>
            /// <param name="cs"></param>
            /// <param name="pcfs"></param>
            /// <param name="fileName"></param>
            static void RemovePartialMenu(CustomizationSection cs, PartialCuiFileCollection pcfs, string fileName)
            {
                //Acad2008执行RemovePartialMenu会移除了pcfs元素和MainCui的元素
                //Acad2021执行RemovePartialMenu是true,但是没有和Acad08一样
                var aa2 = cs.RemovePartialMenu(fileName, null);//移除局部cui
                if (aa2 && pcfs.Contains(fileName))
                {
                    pcfs.Remove(fileName);
    
                    // 如果Acad2021移除失败了,证明了是第一次移除,可能存在cuix的错误导致.
                    // 利用lisp语句移除是正确的,此命令会导致成功修复了某些东西.
                    // 毕竟修复了一次之后执行上面就是正确的了,不知道怎么复现.
                    SendCmd("_.CuiUnLoad", new string[] { fileName });
    
                    // https://adndevblog.typepad.com/autocad/2012/07/unload-partial-cuix-when-autocad-quits.html
                    // 这句无法工作
                    // var aa3 = Acap.UnloadPartialMenu(fileName);//卸载局部cui
                }
            }
    
            /// <summary>
            /// 路径或(文件名.后缀)获取文件名,因为不存在cui路径时候会未融入
            /// </summary>
            /// <param name="fileOrPath"></param>
            /// <returns></returns>
            static string GetFileName(string fileOrPath)
            {
                var a = fileOrPath.LastIndexOf('\') + 1;
                var b = fileOrPath.LastIndexOf('.');
                var groupName = fileOrPath.Substring(a, b - a);
                return groupName;
            }
    
            /// <summary>
            /// 以lisp的方式发送命令
            /// </summary>
            /// <param name="cuiFile"></param>
            static void SendCmd(string cmd, string[] args)
            {
                Document doc = Application.DocumentManager.MdiActiveDocument;
    
                object oldCmdEcho = Application.GetSystemVariable("CMDECHO");
                object oldFileDia = Application.GetSystemVariable("FILEDIA");
    
                Application.SetSystemVariable("CMDECHO", 0);
                Application.SetSystemVariable("FILEDIA", 0);
    
                //界面还没准备好导致这里会出错
                var arg = new StringBuilder();
                foreach (var item in args)
                {
                    arg.Append(item);
                }
                doc.SendStringToExecute(cmd + " " + arg + " ", false, false, false);
                doc.SendStringToExecute("(setvar "FILEDIA" " + oldFileDia.ToString() + ")(princ) ", false, false, false);
                doc.SendStringToExecute("(setvar "CMDECHO" " + oldCmdEcho.ToString() + ")(princ) ", false, false, false);
            }
        }
    }
    

    CuiStatic类

    using System.Runtime.InteropServices;
    using Autodesk.AutoCAD.Customization;
    
    namespace JoinBox.Menu
    {
        public static class CuiStatic
        {
    #if NET35
            //为了让Acad2008配合高版本的API,所以写了个拓展方法给它
            public static bool RemovePartialMenu(this CustomizationSection cs, string fileName, string menuGroupName)
            {
                return cs.RemovePartialMenu(fileName);//卸载局部cui
            }
    #endif
    
    #if NET35
            /// <summary>
            /// 重新载入CUI文件,刷新当前工作区2008
            /// </summary>
            /// <returns></returns>
            [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedReloadMenus")]
            public static extern int CuiAcedReloadMenus();
    #else
        
           /* 这里未能详尽所有的版本 .*/
        
            /// <summary>
            /// 重新载入CUI文件,刷新当前工作区2021
            /// </summary>
            /// <returns></returns>
            [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "?acedReloadMenus@@YAX_N@Z")]
            public static extern int CuiAcedReloadMenus();
    #endif
        }
    }
    

    20210528更新,详尽所有的版本

    上面的 /* 这里未能详尽所有的版本 .*/ 标记的入口点不一样,但是有规律,所以可以参考此处代码:

    JoinBoxCurrency.PeInfo 参考 测试篇 c#读PE32PE32+

    namespace JoinBox.Menu
    {
        public static class CuiStatic
        {
    /// <summary>
    /// 重新载入CUI文件,刷新当前工作区
    /// </summary>
    /// <returns></returns>
    public static int CuiAcedReloadMenus()
    {
        string funcName = "acedReloadMenus";
        // 路径通过程序集就能拿到
        var acadexeName = Process.GetCurrentProcess().MainModule.FileName;
    
        bool getYes = false;
        //输出所有的函数名
        var pe = new JoinBoxCurrency.PeInfo(acadexeName);
        var sb = new StringBuilder();
        foreach (var name in pe.ExportDirectory.NameList)
        {
            sb.Append(Environment.NewLine);
            var str = Encoding.Default.GetString(name as byte[]);
            if (str.Contains(funcName))
            {
                funcName = str;
                getYes = true;
                break;
            }
            sb.Append(str);
        }
        // Debug.WriteLine(sb.ToString());
        if (!getYes)
        {
            throw new Exception("没有找到对应的函数");
        }
    
        IntPtr hModule = Win32API.WinApi.GetModuleHandle(acadexeName); // 执行前必须加载了先...
        if (hModule == IntPtr.Zero)
            throw new Exception("找不到模块:" + acadexeName + "当前程序没有加载这个东西?");
    
        //函数指针
        IntPtr funcAdress = Win32API.WinApi.GetProcAddress(hModule, funcName);
        if (funcAdress == IntPtr.Zero)
            throw new Exception("找不到函数入口点:" + funcAdress);
    
        //利用委托调用函数指针,从而实现对方法的调用.
        var deFunc = Marshal.GetDelegateForFunctionPointer(funcAdress, typeof(DelegateAcedReloadMenus)) as DelegateAcedReloadMenus;
        return deFunc.Invoke();//调用方法(刷新cad的cui)
    }
    
    //委托,调用函数指针
    delegate int DelegateAcedReloadMenus();
    }}
    

    ToolBar工具条

    using System.Diagnostics;
    using System.Collections.Generic;
    using System.Linq;
    using Autodesk.AutoCAD.Customization;
    using Autodesk.AutoCAD.ApplicationServices;
    using Autodesk.AutoCAD.Runtime;
    
    namespace JoinBox.Menu
    {
        public class ToolBar
        {
            [CommandMethod("TestToolBarClose")]
            public void TestToolBarClose()
            {
                var cuiMain = Cui.CuiMain(out string expand);
                ToolBarGetExistsPrint(cuiMain);
    
                //关闭工具条
                ToolBarClose(cuiMain, "YQARCH");
                //ToolBarClose(cuiMain, "MINI");
                //ToolBarClose(cuiMain, "ACAD");
            }
    
            /// <summary>
            /// 打印当前工作空间显示的工具条id
            /// </summary>
            public static void ToolBarGetExistsPrint(CustomizationSection cs)
            {
                List<string> lst = new();
                //当前使用的工作空间
                string wscurrent = (string)Application.GetSystemVariable("wscurrent");
                foreach (Workspace pace in cs.Workspaces)//工作空间 "二维草图与注释"
                {
                    var cs2 = pace.CustomizationSection;//空间下的cui
                    if (wscurrent != pace.Name)//当前空间
                    {
                        continue;
                    }
    
                    Debug.WriteLine("**当前使用的空间名字:" + pace.Name);
                    Debug.WriteLine("**此空间的Cui文件:" + cs2.CUIFileName);
                    foreach (Toolbar tb in cs2.MenuGroup.Toolbars)
                    {
                        if (tb.ToolbarVisible == ToolbarVisible.hide)
                        {
                            lst.Add(tb.ElementID);
                        }
                    }
                    break;
                    //foreach (WorkspaceToolbar tb in pace.WorkspaceToolbars)//工具条
                    //{
                    //    if (tb.Display == 0)//会遍历到其他空间可展示的东西
                    //    {
                    //        lst.Add(tb.ElementID);
                    //    }
                    //}
                }
                //按照字母排序,打印目前已经存在的工具条
                lst = lst.OrderBy(elementID => elementID).ToList();
                foreach (var item in lst)
                {
                    Debug.WriteLine(item);
                }
            }
    
            /// <summary>
            /// 关闭工具条
            /// </summary>
            public static void ToolBarClose(CustomizationSection cs, string cuiMenuGroupName)
            {
                //当前使用的工作空间
                string wscurrent = (string)Application.GetSystemVariable("wscurrent");
                foreach (Workspace pace in cs.Workspaces)//工作空间 "二维草图与注释"
                {
                    if (wscurrent != pace.Name)//当前空间
                    {
                        continue;
                    }
                    foreach (WorkspaceToolbar tb in pace.WorkspaceToolbars)//工具条
                    {
                        if (tb.MenuGroup == cuiMenuGroupName)
                        {
                            pace.WorkspaceToolbars.Remove(tb);//卸载工具条
                        }
                    }
                    break;
                }
            }
        }
    }
    

    相关阅读

    cad.net 更改高版本填充交互方式为低版本样子

    南胜博客,自动生成cuix

    Ribbon

    官方博客工具条了

    [尼克劳斯] https://www.cnblogs.com/bomb12138/p/3607990.html

    (完)

  • 相关阅读:
    Python基本数据类型(int str)个人笔记
    LINUX简单操作的笔记
    samba服务配置步骤
    IP地址的初步理解
    apache服务配置步骤
    [已解决]This dependency was not found: * common/stylus/index.styl in ./src/main.js To install it, you can run: npm install --save common/stylus/index.styl
    (转)iFrame高度自适应
    (转)Div左右两侧等高
    (转)Css样式兼容IE6,IE7,FIREFOX的写法
    瀑布流布局代码
  • 原文地址:https://www.cnblogs.com/JJBox/p/14676302.html
Copyright © 2020-2023  润新知