zoukankan      html  css  js  c++  java
  • 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

    (完)

  • 相关阅读:
    Single Number II
    Pascal's Triangle
    Remove Duplicates from Sorted Array
    Populating Next Right Pointers in Each Node
    Minimum Depth of Binary Tree
    Unique Paths
    Sort Colors
    Swap Nodes in Pairs
    Merge Two Sorted Lists
    Climbing Stairs
  • 原文地址:https://www.cnblogs.com/JJBox/p/14676302.html
Copyright © 2011-2022 走看看