using Autodesk.Windows;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Media.Imaging;
using System.Xml;
namespace Lad.Ribbons
{
///
/// 从配置文件初始化菜单
///
public class RibbonInitConfig : IRibbonAbs
{
private RibbonControl? control;
private IRibbonUI ribbon;
private Assembly? asm;
private string configPath;
private Type? RibbonType;
protected Action CommandBase = e => System.Windows.MessageBox.Show("未绑定命令");
public RibbonInitConfig(IRibbonUI ribbonUI, string configPath) : base()
{
this.ribbon = ribbonUI;
this.RibbonType = ribbonUI.GetType();
this.asm = Assembly.GetAssembly(RibbonType);
this.configPath = configPath;
}
#region 功能区回调
const string RibbonRootNode = "Ribbon";
const string RibbonTabNode = "RibbonTab";
const string RibbonPanelNode = "RibbonPanel";
const string RibbonItemNodeName = "RibbonButton";
const string CommondAttribute = "Command";
const string RibbonToolTipNode = "RibbonToolTip";
public void Init()
{
this.InitRibbon(control =>
{
this.control = control;
var xdoc = GetResourceXmlDoc(asm, configPath);
foreach (var tab in InitRibbonTabs(xdoc))
{
this.Tab = tab.Tab;
foreach (var panel in InitRibbonPanels(tab.Node))
{
var tempPanel = panel.Panel;
foreach (var btnItem in InitRibbonItems(panel.Node))
{
if (btnItem.Item == null) continue;
RibbonItem? tempBtn = null;
if ((tempBtn = tempPanel.Source.Items.Where(b => b.Text == btnItem.Item.Text).FirstOrDefault()) != null)
tempPanel.Source.Items.Remove(tempBtn);
btnItem.Item.ToolTip = InitRibbonToolTip(btnItem.Node);
tempPanel.Source.Items.Add(btnItem.Item);
}
}
}
});
}
#endregion
#region Ribbon帮助
///
/// 初始化选项卡
///
///
///
IEnumerable<(RibbonTab Tab, XmlNode Node)> InitRibbonTabs(XmlDocument? xmlDoc)
{
return xmlDoc?.SelectNodes($"/{RibbonRootNode}/{RibbonTabNode}")?.ForEach().Select(xmlNode =>
{
RibbonTab? temp = (!string.IsNullOrWhiteSpace(xmlNode.Attributes["Id"]?.Value) ? control?.FindTab(xmlNode.Attributes["Id"]?.Value) : null);
bool isNew = temp == null;
RibbonTab ribbonTab = temp ?? new RibbonTab();
foreach (XmlAttribute attribute in xmlNode.Attributes)
SetProperty(ribbonTab, attribute);
if (isNew) control?.Tabs.Add(ribbonTab);
return (ribbonTab, xmlNode);
}) ?? Enumerable.Empty<(RibbonTab Tab, XmlNode Node)>();
}
///
/// 初始化面板
///
///
///
IEnumerable<(RibbonPanel Panel, XmlNode Node)> InitRibbonPanels(XmlNode xmlNode)
{
return xmlNode?.SelectNodes(RibbonPanelNode)?.ForEach().Select(node =>
{
RibbonPanel? temp = (!string.IsNullOrWhiteSpace(node.Attributes["Id"]?.Value) ? this.Tab?.FindPanel(node.Attributes["Id"]?.Value) : null);
bool isNew = temp == null;
RibbonPanel panel = temp ?? new();
RibbonPanelSource panelSource = panel.Source ?? new();
foreach (XmlAttribute panelAttribute in node.Attributes)
SetProperty(panelSource, panelAttribute);
if (isNew)
{
panel.Source = panelSource;
this.Tab?.Panels.Add(panel);
}
return (panel, node);
}) ?? Enumerable.Empty<(RibbonPanel? Panel, XmlNode Node)>();
}
///
/// 初始化RibbonItem
///
///
///
IEnumerable<(RibbonItem? Item, XmlNode Node)> InitRibbonItems(XmlNode xmlNode)
{
if (RibbonType == null) return Enumerable.Empty<(RibbonItem? Item, XmlNode Node)>();
return xmlNode?.SelectNodes(RibbonItemNodeName)?.ForEach().Select(node =>
{
var type = Assembly.GetAssembly(typeof(RibbonItem)).GetType($"Autodesk.Windows.{node.Name}");
if (type != null)
{
var ribbonButton = System.Activator.CreateInstance(type);
//设置RibbonItem的属性
foreach (XmlAttribute btnAttribute in node.Attributes)
{
if (string.IsNullOrWhiteSpace(btnAttribute.Value)) continue;
//根据特性名判断是否为命令
if (CommondAttribute == btnAttribute.Name && typeof(RibbonCommandItem).IsAssignableFrom(type))
{
var proinfo = type.GetProperty(RibbonCommandItem.CommandHandlerPropertyName);
var commodMethod = (RibbonType.GetMethods().Where(m => m.Name == btnAttribute.Value && m.GetParameters().Length == 1
&& m.GetParameters()[0].ParameterType == typeof(object)).FirstOrDefault());
Action? doExecute = null;
if (commodMethod == null)
{
var pinfoMethod = RibbonType.GetProperties().Where(p => p.Name == btnAttribute.Value && typeof(Action)
.IsAssignableFrom(p.PropertyType)).FirstOrDefault()?.GetGetMethod();// 判断是否存在委托类型的属性
if (pinfoMethod != null)
doExecute = pinfoMethod.Invoke(pinfoMethod.IsStatic ? null : ribbon, null) as Action;
}
else
doExecute = Delegate.CreateDelegate(typeof(Action), commodMethod.IsStatic ? null : ribbon, commodMethod) as Action;
proinfo.SetValue(ribbonButton, new CommandBase() { DoCanExecute = e => true, DoExecute = doExecute ?? CommandBase }, null);
}
//根据特性名称获取对应的属性
if (CommondAttribute != btnAttribute.Name)
{
var propertyInfo = type.GetProperty(btnAttribute.Name);
if (propertyInfo == null) continue;
if (propertyInfo.PropertyType.Equals(typeof(System.Windows.Media.ImageSource)))
{
BitmapImage? image;
if ((image = GetImageResource(asm, btnAttribute.Value)) != null)
propertyInfo.SetValue(ribbonButton, image, null);
}
else
propertyInfo.SetValue(ribbonButton, propertyInfo.PropertyType.IsEnum ? Enum.Parse(propertyInfo.PropertyType, btnAttribute.Value)
: Convert.ChangeType(btnAttribute.Value, propertyInfo.PropertyType), null);
}
}
return (ribbonButton as RibbonItem, node);
}
return (default, node);
}) ?? Enumerable.Empty<(RibbonItem? Item, XmlNode Node)>();
}
///
/// 初始化提示
///
///
///
RibbonToolTip? InitRibbonToolTip(XmlNode xmlNode)
{
var node = xmlNode?.SelectSingleNode(RibbonToolTipNode);
if (node == null) return null;
RibbonToolTip toolTip = new();
foreach (XmlAttribute attribute in node.Attributes)
{
var propertyInfo = typeof(RibbonToolTip).GetProperty(attribute.Name);
if (propertyInfo == null) continue;
if (propertyInfo.PropertyType.Equals(typeof(System.Windows.Media.ImageSource)))
{
BitmapImage? image;
if ((image = GetImageResource(asm, attribute.Value)) != null)
propertyInfo.SetValue(toolTip, image, null);
}
else
propertyInfo.SetValue(toolTip, propertyInfo.PropertyType.IsEnum ? Enum.Parse(propertyInfo.PropertyType, attribute.Value)
: Convert.ChangeType(attribute.Value, propertyInfo.PropertyType), null);
}
return toolTip;
}
///
/// 根据节点属性设置对象的属性
///
///
/// 实例对象
///
void SetProperty(T info, XmlAttribute attribute) where T : class
{
var propertyInfo = typeof(T).GetProperty(attribute.Name);
propertyInfo?.SetValue(info, propertyInfo.PropertyType.IsEnum ? Enum.Parse(propertyInfo.PropertyType, attribute.Value)
: Convert.ChangeType(attribute.Value, propertyInfo.PropertyType), null);
}
#endregion
#region 帮助器
///
/// 获取程序集的资源图片
///
///
/// 图片路径
///
private BitmapImage? GetImageResource(Assembly? asm, string resourceName)
{
if (string.IsNullOrWhiteSpace(resourceName) || asm == null) return null;
var resourcefileName = asm.GetManifestResourceNames()
.Where(s => s.Contains(resourceName.Replace(@"\", ".")))
.FirstOrDefault();
if (!string.IsNullOrWhiteSpace(resourcefileName))
return RibbonExtensions.SteamToBitmapImage(asm.GetManifestResourceStream(resourcefileName));
if (!string.IsNullOrWhiteSpace(asm.Location) && !string.IsNullOrEmpty(resourceName))
{
var dirPath = Directory.GetParent(asm.Location).FullName;
if (File.Exists(dirPath + resourceName))
return new(new(dirPath + resourceName));
if (dirPath.DirExists(resourceName.Substring(resourceName.LastIndexOf(@"\") + 1), out var path))
return new(new(path));
}
return null;
}
///
/// 获取调用程序集的配置文档
///
///
///
///
private XmlDocument? GetResourceXmlDoc(Assembly? asm, string resourceName)
{
if (asm != null)
{
var resourcefileName = asm.GetManifestResourceNames()
.Where(s => string.Compare(resourceName, s, StringComparison.OrdinalIgnoreCase) == 0)
.FirstOrDefault();
if (!string.IsNullOrWhiteSpace(resourcefileName))
{
using (StreamReader resourceReader = new StreamReader(asm.GetManifestResourceStream(resourcefileName)))
{
if (resourceReader != null)
{
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(resourceReader);
return xmlDoc;
}
}
}
}
return null;
}
#endregion
}
}
扩展函数
using Autodesk.Windows;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Media.Imaging;
using System.Xml;
namespace Lad.Ribbons
{
public static class RibbonExtensions
{
///
/// 遍历节点
///
///
///
internal static IEnumerable ForEach(this XmlNodeList nodeList)
{
foreach (XmlNode node in nodeList)
yield return node;
}
internal static BitmapImage? SteamToBitmapImage(Stream stream)
{
return stream == null ? null : BitmapToBitmapImage(new(stream));
}
// Bitmap --> BitmapImage
internal static BitmapImage? BitmapToBitmapImage(System.Drawing.Bitmap bitmap)
{
if (bitmap == null)
return null;
using (MemoryStream stream = new MemoryStream())
{
bitmap.Save(stream, System.Drawing.Imaging.ImageFormat.Png); // 坑点:格式选Bmp时,不带透明度
stream.Position = 0;
BitmapImage result = new BitmapImage();
result.BeginInit();
// According to MSDN, "The default OnDemand cache option retains access to the stream until the image is needed."
// Force the bitmap to load right now so we can dispose the stream.
result.CacheOption = BitmapCacheOption.OnLoad;
result.StreamSource = stream;
result.EndInit();
result.Freeze();
return result;
}
}
///
/// 面板中添加功能按钮
///
///
/// 按钮组
public static void AddRibbonItems(this RibbonPanel panel, params RibbonItem[] ribbonItems)
{
if (panel == null) throw new ArgumentNullException("RibbonPanel");
foreach (var item in ribbonItems)
if (!panel.Source.Items.Any(b => b.Text == item.Text))
panel.Source.Items.Add(item);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Lad.Ribbons
{
internal static class FilePathExtension
{
///
/// 程序集目录下的子文件夹是否包含配置文件
///
/// 搜索的文件目录
/// 搜索的文件名
/// 文件路径
/// 是否存在
public static bool DirExists(this string dirFullName, string searchName, out string path)
{
foreach (var dir in System.IO.Directory.GetDirectories(dirFullName))
{
path = System.IO.Path.Combine(dir, searchName);
if (System.IO.File.Exists(path))
return true;
else
{
if (DirExists(dir, searchName, out path))
return true;
}
}
path = string.Empty;
return false;
}
}
}
使用示例2
RibbonInit ribbonInit = new RibbonInit("我的选项卡", "1001");
ribbonInit.Init(tab =>
{
ribbonInit.CreatePanel("信息管理", "10011")
.AddRibbonItems(new RibbonItem[] {
ribbonInit.CreatLargeButton("查询", e =>
{
var button = e as RibbonButton;
if (button.CommandParameter != null)//命令行发送命令
{
Document doc = AcadApp.DocumentManager.MdiActiveDocument;
doc.SendStringToExecute(button.CommandParameter.ToString(), true, false, false);
}
}, default, "Line ")
});
});