参考王磊老师编写的 AutoCAD Civil 3D .NET二次开发,基本实现了功能区。

完成后效果:

今天的代码比较坎坷,主要有以下几个坑:

  1. 需要创建图标,并添加到资源中:
  2. RibbonButton存在多个引用,不知道选用哪个,通过测试,选用了using Autodesk.Windows;
  3. Orientation.Vertical需要引用Assembly:PresentationFramework.dll,刚开始一直没发现,后再在MSDN上找到了:

    代码如下

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using Autodesk.AutoCAD.ApplicationServices.Core;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.Windows;
using Civil3DTools.Properties;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;

namespace Civil3DTools
{
    internal class RibbonDemo
    {
        private const int large = 32;
        private const int small = 16;
        private static Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;

        /// <summary>
        ///     创建标准按钮
        /// </summary>
        /// <param name="bmp"></param>
        /// <param name="text"></param>
        /// <param name="toolTip"></param>
        /// <param name="command"></param>
        /// <returns></returns>
        private static RibbonButton CreateStdBtn(Bitmap bmp, string text, string toolTip, string command)
        {
            var rb = new RibbonButton(); //创建新按钮
            rb.Image = Images.getBitmap(bmp, small); //设置标准图标
            rb.Text = text; //设置文本
            rb.ToolTip = toolTip; //设置提示
            rb.CommandParameter = command; //设置命令名称
            rb.ShowText = true; //显示文本
            rb.CommandHandler = new RibbonbtnCmdHandle(); //设置命令处理程序
            return rb;
        }

        /// <summary>
        ///     创建大图标按钮
        /// </summary>
        /// <param name="bmp"></param>
        /// <param name="text"></param>
        /// <param name="toolTip"></param>
        /// <param name="command"></param>
        /// <returns></returns>
        private static RibbonButton CreateLargeBtn(Bitmap bmp, string text, string toolTip, string command)
        {
            var rb = CreateStdBtn(bmp, text, toolTip, command);
            rb.LargeImage = Images.getBitmap(bmp, large); //设置大图标
            rb.Size = RibbonItemSize.Large; //设置图标尺寸
            rb.Orientation = Orientation.Vertical;
            return rb;
        }

        /// <summary>
        ///     在附加模块选项卡中添加面板
        /// </summary>
        public static void AddAddinTab()
        {
            var rc = ComponentManager.Ribbon;
            RibbonTab rt = null;
            foreach (var tab in rc.Tabs) //查找附加模块选项卡
                if (tab.AutomationName == "附加模块") //根据名称查找
                {
                    rt = tab;
                    break;
                }

            if (rt == null) //没找到的话新建一个
            {
                rt = new RibbonTab();
                rt.Title = "附加模块";
                rt.Id = "CIVIL.ID_CIVIL 3DAddins"; //设置标题
                rc.Tabs.Add(rt); //设置ID
            }

            var rps = new RibbonPanelSource(); //面板资源
            rps.Title = "BJUCD"; //面板标题
            var rp = new RibbonPanel(); //新建面板
            rp.Source = rps; //设置面板资源
            rt.Panels.Insert(0, rp); //将面板插入到选项卡中
            var rb = CreateLargeBtn( //创建大图标按钮
                Resources.TableOut, //图标
                "输出\nCivil 3D表格", //标题文本
                "将Civil 3D表格输出为.csv格式文件", //提示信息
                " .CTTC "); //命令名称,主要保留空格
            rps.Items.Add(rb); //将大图标按钮添加到面板资源中
            var rrp = new RibbonRowPanel(); //新建“行面板”
            rrp.MinWidth = 150;
            rps.Items.Add(new RibbonSeparator()); //插入分隔符
            rps.Items.Add(rrp); //将“行面板”添加到面板资源中
            var rb1 = CreateStdBtn( //创建标准大小图标按钮
                Resources.table, //图标
                "逐桩坐标表", //标题文本
                "创建逐桩坐标表", //提示信息
                " .StationTable "); //命令名称
            var rb2 = CreateStdBtn( //创建标准大小图标按钮
                Resources.Label, //图标
                "路线偏移标签", //标题文本
                "创建路线偏移标签", //提示信息
                " .OffsetLabel "); //命令名称
            rrp.Items.Add(rb1); //将按钮添加到“行面板”
            rrp.Items.Add(new RibbonRowBreak()); //添加“换行符”
            rrp.Items.Add(rb2); //将按钮添加到“行面板”
        }
    }

    /// <summary>
    ///     根据按钮的命令参数执行相应的命令
    /// </summary>
    internal class RibbonbtnCmdHandle : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object patameter)
        {
            if (patameter is RibbonButton)
            {
                var rb = patameter as RibbonButton;
                Application.DocumentManager.MdiActiveDocument.SendStringToExecute((string) rb.CommandParameter, true,
                    false, false);
            }
        }
    }

    /// <summary>
    ///     将图片转换为ImageSource
    /// </summary>
    internal class Images
    {
        public static double m_DpiScale = 1.0;

        public static BitmapImage getBitmap(Bitmap image, int l)
        {
            var stream = new MemoryStream();
            image.Save(stream, ImageFormat.Png);
            var bmp = new BitmapImage();
            bmp.BeginInit();
            bmp.StreamSource = stream;
            bmp.DecodePixelHeight = (int) (l * m_DpiScale);
            bmp.DecodePixelWidth = (int) (l * m_DpiScale);
            bmp.EndInit();
            return bmp;
        }

        [DllImport("user32.dll")]
        private static extern IntPtr GetDC(IntPtr ptr);

        [DllImport("user32.dll", EntryPoint = "ReleaseDC")]
        private static extern IntPtr ReleaseDC(IntPtr pre, IntPtr hDc);

        [DllImport("gdi32.dll")]
        private static extern int GetDeviceCaps(IntPtr hDc, int nIndex);

        [DllImport("user32.dll")]
        internal static extern bool SetProcessDPIAware();

        public static void GetDpiScale() //根据DPI对图标进行缩放
        {
            try
            {
                SetProcessDPIAware();
                var screenDC = GetDC(IntPtr.Zero);
                var dpi = GetDeviceCaps(screenDC, 90);
                m_DpiScale = dpi / 96.0;
                ReleaseDC(IntPtr.Zero, screenDC);
            }
            catch (Exception ex)
            {
                Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.Message);
            }
        }
    }
    /// <summary>
    /// 在程序加载时自动创建面板,每次运行都会创建一个面板,先将其注释掉
    /// </summary>
    //public class MyPlugin : IExtensionApplication
    //{
    //    public void Initialize()
    //    {
    //        Images.GetDpiScale();
    //        Application.Idle += LoadMyRibbon;
    //    }

    //    public void Terminate()
    //    {
    //    }

    //    private void LoadMyRibbon(object sender, EventArgs e)
    //    {
    //        RibbonDemo.AddAddinTab();
    //        Application.Idle -= LoadMyRibbon;
    //    }
    //}
}

今天有些匆忙,没有好好写注释,代码理解也不深入,晚上要加班了。