Files
ShrlAlgoToolkit/Sai.Toolkit.Revit/Assist/UIAssist.cs
2024-09-22 11:05:41 +08:00

639 lines
21 KiB
C#
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using UIFramework;
using UIFrameworkServices;
using adWin = Autodesk.Windows;
namespace Sai.Toolkit.Revit.Assist;
public static class UIAssist
{
private static readonly string AddInPath = typeof(UIAssist).Assembly.Location;
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool SetWindowText(IntPtr hWnd, string lpString);
private static BitmapSource ToBitmapSource(Bitmap bitmap)
{
return bitmap == null
? null
: Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}
/// <summary>
/// Combobox是可以分组的
/// 组合框是与事件结合使用的
/// </summary>
public static ComboBox AddComboBox(
this RibbonPanel panel,
ComboBoxData comboBoxData,
params ComboBoxMemberData[] memberData
)
{
var comboBx = panel.AddItem(comboBoxData) as ComboBox ?? throw new ArgumentNullException(nameof(comboBoxData));
foreach (var item in memberData)
{
comboBx.AddItem(item);
}
comboBx.CurrentChanged += (sender, _) =>
{
if (sender is ComboBox comboBox)
{
var member = comboBox.Current;
TaskDialog.Show("组合框选择", "你的选择是: " + member.ItemText);
}
};
return comboBx;
}
/// <summary>
/// 在Revit现有的标签下如不存在则创建创建创建面板
/// </summary>
/// <param name="application"></param>
/// <param name="panelName">创建的面板名称</param>
/// <param name="tabName">若Tab不存在则创建对应名称的Tab</param>
/// <returns></returns>
public static RibbonPanel AddPanel(this UIControlledApplication application, string panelName, string tabName)
{
var ribbonTab = adWin.ComponentManager.Ribbon.Tabs.FirstOrDefault(tab => tab.Id.Equals(tabName));
if (ribbonTab is null)
{
application.CreateRibbonTab(tabName);
return application.CreateRibbonPanel(tabName, panelName);
}
var ribbonPanel = application.GetRibbonPanels(tabName).Find(panel => panel.Name.Equals(panelName));
return ribbonPanel ?? application.CreateRibbonPanel(tabName, panelName);
}
/// <summary>
/// 创建一个下拉式按钮。
/// </summary>
/// <param name="pnl">面板</param>
/// <param name="name">下拉按钮名称</param>
/// <param name="pbds"></param>
/// <returns></returns>
public static PulldownButton AddPullDownButton(this RibbonPanel pnl, string name, params PushButtonData[] pbds)
{
if (pnl is null)
{
throw new ArgumentNullException(nameof(pnl));
}
if (pbds is null)
{
throw new ArgumentNullException(nameof(pbds));
}
var pbd = new PulldownButtonData(name, name);
if (pnl.AddItem(pbd) is not PulldownButton result)
{
throw new InvalidCastException();
}
result.ToolTip = pbd.ToolTip;
result.LongDescription = pbd.LongDescription;
result.LargeImage = pbd.LargeImage;
foreach (var pbdl in pbds)
{
var btn = result.AddPushButton(pbdl);
if (btn is null)
{
continue;
}
btn.ToolTip = pbdl.ToolTip;
btn.LongDescription = pbdl.LongDescription;
btn.LargeImage = pbdl.LargeImage;
}
return result;
}
/// <summary>
/// 添加按钮
/// </summary>
/// <typeparam name="T">命令类</typeparam>
/// <param name="panel">面板</param>
/// <param name="text">按钮名</param>
/// <param name="bitmap">按钮图片</param>
/// <param name="tooltip"></param>
/// <param name="availabilityClassName">控制可用性</param>
public static PushButtonData AddPushButton<T>(this RibbonPanel panel)
where T : class, IExternalCommand
{
var data = new PushButtonData(typeof(T).FullName, "外部命令", typeof(T).Assembly.Location, typeof(T).FullName);
panel.AddItem(data);
return data;
}
/// <summary>
/// 单选框
/// </summary>
/// <param name="pnl">面板</param>
/// <param name="groupName">分组名称</param>
/// <param name="toggleButtonData"></param>
/// <returns></returns>
public static RadioButtonGroup AddRadioButtonGroup(
this RibbonPanel pnl,
string groupName,
params ToggleButtonData[] toggleButtonData
)
{
if (pnl is null)
{
throw new ArgumentNullException(nameof(pnl));
}
if (string.IsNullOrEmpty(groupName))
{
throw new ArgumentNullException(nameof(groupName));
}
RadioButtonGroupData groupData = new(groupName);
var radioButtonGroup = (RadioButtonGroup)pnl.AddItem(groupData);
foreach (var data in toggleButtonData)
{
radioButtonGroup.AddItem(data);
}
return radioButtonGroup;
}
/// <summary>
/// 创建一个分割记忆按钮。
/// </summary>
/// <param name="pnl">面板</param>
/// <param name="pnl">名称</param>
/// <param name="array"></param>
/// <returns></returns>
public static SplitButton AddSplitButton(this RibbonPanel pnl, string name, params PushButtonData[] array)
{
if (pnl is null)
{
throw new ArgumentNullException(nameof(pnl));
}
if (array is null)
{
throw new ArgumentNullException(nameof(array));
}
if (string.IsNullOrEmpty(name) || string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException(nameof(array));
}
var splitButton = new SplitButtonData(name, name);
if (pnl.AddItem(splitButton) is not SplitButton result)
{
throw new InvalidCastException();
}
result.ToolTip = splitButton.ToolTip;
result.LongDescription = splitButton.LongDescription;
result.LargeImage = splitButton.LargeImage;
foreach (var buttonData in array)
{
result.AddPushButton(buttonData);
}
return result;
}
public static void AddStackItems(this adWin.RibbonRowPanel rowPanel, params adWin.RibbonButton[] ribbonButtons)
{
for (var i = 0; i < ribbonButtons.Length; i++)
{
rowPanel.Items.Add(ribbonButtons[i]);
if (i < ribbonButtons.Length - 1)
{
//行打断=新建行
rowPanel.Items.Add(new adWin.RibbonRowBreak());
}
}
}
public static void AddTextBox(this RibbonPanel panel, TextBoxData txtBoxData)
{
var txtBox = panel.AddItem(txtBoxData) as TextBox;
txtBox!.PromptText = "输入提示";
txtBox.ShowImageAsButton = true;
txtBox.EnterPressed += (sender, _) =>
{
if (sender is TextBox textBox)
{
TaskDialog.Show("文本输入", "输入内容: " + textBox.Value);
}
};
txtBox.Width = 180;
}
public static ToggleButton AddToggleButton<T>(this RadioButtonGroup group, string name)
where T : IExternalCommand
{
//var addInPath = typeof(T).Assembly.Location;
var toggleData = new ToggleButtonData(name, name, typeof(T).Assembly.Location, typeof(T).FullName);
return group.AddItem(toggleData);
}
/// <summary>
/// 帮助文档
/// </summary>
/// <param name="helpFileSafeName">"xxx.chm"</param>
/// <returns></returns>
public static ContextualHelp CreateContextualHelp(string helpFileSafeName)
{
//addin目录
FileInfo fileInfo = new(Assembly.GetExecutingAssembly().Location);
var text = Path.Combine(fileInfo.Directory!.FullName, helpFileSafeName);
if (new FileInfo(text).Exists)
{
return new ContextualHelp(ContextualHelpType.Url, text);
}
ImageAssist.ExtractResource(helpFileSafeName, text);
return new ContextualHelp(ContextualHelpType.ChmFile, text);
}
/// <summary>
/// 添加按钮
/// </summary>
/// <typeparam name="T">命令类</typeparam>
/// <param name="panel">面板</param>
/// <param name="text">按钮名</param>
/// <param name="bitmap">按钮图片</param>
/// <param name="tooltip"></param>
/// <param name="availabilityClassName">控制可用性</param>
public static PushButtonData CreatePushButton<T>(string name)
where T : class, IExternalCommand
{
return new PushButtonData(typeof(T).FullName, name, typeof(T).Assembly.Location, typeof(T).FullName);
}
/// <summary>
/// 查找内容
/// </summary>
/// <param name="hwndParent"></param>
/// <param name="hwndChildAfter"></param>
/// <param name="lpszClass"></param>
/// <param name="lpszWindow"></param>
/// <returns></returns>
[DllImport("user32.dll", EntryPoint = "FindWindowEx", SetLastError = true, CharSet = CharSet.Unicode)]
private static extern IntPtr FindWindowEx(
IntPtr hwndParent,
IntPtr hwndChildAfter,
string lpszClass,
string lpszWindow
);
public static ToggleButton GetToggleButton(this RadioButtonGroup radioButtonGroup)
{
return radioButtonGroup.Current;
}
/// <summary>
/// Revit默认打开文件对话框
/// </summary>
/// <param name="filter">多个过滤器之间用”|“分隔,例如:"Revit文件(*.rfa;*.rvt;*.rft;*.rte;)|*.rfa;*.rvt;*.rft;*.rte"</param>
/// <returns></returns>
public static string OpenFile(string filter)
{
string filename = null;
FileOpenDialog openFileDialog =
new(filter)
{
DefaultFilterEntry = filter,
ShowPreview = true,
Title = "打开文件"
};
if (openFileDialog.Show() == ItemSelectionDialogResult.Confirmed)
{
var mp = openFileDialog.GetSelectedModelPath();
filename = ModelPathUtils.ConvertModelPathToUserVisiblePath(mp);
}
return filename;
}
public static PushButtonData SetAvailability<T>(this PushButtonData pushButtonData)
where T : IExternalCommandAvailability
{
pushButtonData.AvailabilityClassName = typeof(T).FullName;
return pushButtonData;
}
/// <summary>
/// 指定决定按钮可用性的类别
/// </summary>
/// <param name="button">功能区中将受限制的按钮</param>
/// <typeparam name="T">类型继承 <see cref="Autodesk.Revit.UI.IExternalCommandAvailability"/></typeparam>
/// <remarks>T 类应与插件 "外部命令 "共享同一程序集</remarks>
public static void SetAvailabilityController<T>(this PushButton button)
where T : IExternalCommandAvailability, new()
{
button.AvailabilityClassName = typeof(T).FullName;
}
public static PushButtonData SetDescription(this PushButtonData pushButtonData, string longDescription)
{
pushButtonData.LongDescription = longDescription;
return pushButtonData;
}
/// <summary>
/// 右下角箭头对话框
/// </summary>
public static void SetDialogLauncher(string panelName)
{
var group = adWin.ComponentManager.Ribbon.Tabs
.First()
.Panels.FirstOrDefault(p => p.AutomationName == panelName);
if (group != null)
{
group.Source.DialogLauncher = group.Source.Items.First() as adWin.RibbonCommandItem;
}
}
/// <summary>
/// 右下角箭头对话框
/// </summary>
public static void SetDialogLauncher(this adWin.RibbonPanel panel, adWin.RibbonCommandItem item)
{
if (panel != null)
{
panel.Source.DialogLauncher = item;
}
}
/// <summary>
/// 双击选项
/// </summary>
public static void SetDoubleClickAction(DoubleClickTarget target, DoubleClickAction clickAction)
{
var doubleOpt = DoubleClickOptions.GetDoubleClickOptions();
//DoubleClickAction dca = doubleOpt.GetAction(DoubleClickTarget.Family);
doubleOpt.SetAction(target, clickAction);
}
/// <summary>
/// 提示包含短视频
/// </summary>
/// <param name="pushButtonData"></param>
/// <param name="title"></param>
/// <param name="videoPath"></param>
public static void SetExpandedVideo(this PushButtonData pushButtonData, string title, string videoPath)
{
var internalGetRibbonItemMethod = typeof(RibbonItem).GetMethod(
"getRibbonItem",
BindingFlags.NonPublic | BindingFlags.Instance
);
if (internalGetRibbonItemMethod?.Invoke(pushButtonData, null) is Autodesk.Windows.RibbonButton button)
{
button.ToolTip = new adWin.RibbonToolTip { Title = title, ExpandedVideo = new Uri(videoPath) };
}
}
public static PushButtonData SetImage(this PushButtonData pushButtonData, Bitmap image)
{
pushButtonData.Image = ToBitmapSource(image);
return pushButtonData;
}
public static void SetImage(this RibbonButton button, string uri)
{
button.Image = new BitmapImage(new Uri(uri, UriKind.RelativeOrAbsolute));
}
/// <summary>
/// 消息中心
/// </summary>
/// <param name="head"></param>
/// <param name="content"></param>
public static void SetInfoCenterPaletteMsg(string head, string content)
{
var paletteMgr = Autodesk.Windows.ComponentManager.InfoCenterPaletteManager;
var resultItem = new Autodesk.Internal.InfoCenter.ResultItem
{
Category = head, // 气泡标题
Title = content // 气泡内容
};
resultItem.ResultClicked += (_, _) =>
{
TaskDialog.Show("气泡内容", "点击了气泡内容!");
}; // 当鼠标点击气泡内容时触发此事件
paletteMgr.ShowBalloon(resultItem);
}
public static PushButtonData SetLargeImage(this PushButtonData pushButtonData, Bitmap largeImage)
{
pushButtonData.LargeImage = ToBitmapSource(largeImage);
return pushButtonData;
}
/// <summary>
/// Adds a 32x32px-96dpi image from the URI source
/// </summary>
/// <param name="button">Button to which the icon will be added</param>
/// <param name="uri">Relative or Absolute path to the icon</param>
/// <example>button.SetLargeImage("/RevitAddIn;component/Resources/Icons/RibbonIcon32.png")</example>
public static void SetLargeImage(this RibbonButton button, string uri)
{
button.LargeImage = new BitmapImage(new Uri(uri, UriKind.RelativeOrAbsolute));
}
/// <summary>
/// 状态栏
/// </summary>
/// <param name="msg"></param>
public static void SetRevitStatusBarMsg(string msg)
{
var mainWindowHandle = Process.GetCurrentProcess().MainWindowHandle;
if (mainWindowHandle == IntPtr.Zero)
{
return;
}
var statusBar = FindWindowEx(mainWindowHandle, IntPtr.Zero, "msctls_statusbar32", string.Empty);
if (statusBar != IntPtr.Zero)
{
SetWindowText(statusBar, msg);
}
}
/// <summary>
/// 基于Revit封装的RibbonButton设置其快捷键.
/// </summary>
/// <param name="btn">RibbonButton.</param>
/// <param name="key">快捷键字符串.</param>
/// <returns></returns>
public static bool SetShortCut(this Autodesk.Revit.UI.RibbonButton btn, string key)
{
if (btn == null)
return false;
var item = btn.GetType()
.InvokeMember(
"getRibbonItem",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod,
Type.DefaultBinder,
btn,
null
);
return item != null && (item as Autodesk.Windows.RibbonItem).SetShortCut(key);
}
/// <summary>
/// 基于通用库封装的RibbonCommandItem设置其快捷键.
/// </summary>
/// <param name="commandItem">RibbonCommandItem.</param>
/// <param name="key">快捷键字符串.</param>
/// <returns></returns>
public static bool SetShortCut(this Autodesk.Windows.RibbonItem commandItem, string key)
{
if (commandItem == null || string.IsNullOrEmpty(key))
return false;
Autodesk.Windows.ComponentManager.Ribbon.FindItem(
commandItem.Id,
false,
out var parentPanel,
out var parentTab,
true
);
if (parentTab == null || parentPanel == null)
return false;
var path = string.Format("{0}>{1}", parentTab.Id, parentPanel.Source.Id);
var cmdId = ControlHelper.GetCommandId(commandItem);
if (string.IsNullOrEmpty(cmdId))
{
cmdId = Guid.NewGuid().ToString();
ControlHelper.SetCommandId(commandItem, cmdId);
}
var shortcutItem = new ShortcutItem(commandItem.Text, cmdId, key, path)
{
ShortcutType = StType.RevitAPI
};
UIFrameworkServices.KeyboardShortcutService.applyShortcutChanges(
new Dictionary<string, ShortcutItem>() { { cmdId, shortcutItem } }
);
return true;
}
public static PushButtonData SetShowText(this PushButtonData pushButtonData, string text)
{
pushButtonData.Text = text;
return pushButtonData;
}
public static PushButtonData SetToolTip(this PushButtonData pushButtonData, string tooltip)
{
pushButtonData.ToolTip = tooltip;
return pushButtonData;
}
public static PushButtonData SetToolTipImage(this PushButtonData pushButtonData, Bitmap toolTipImage)
{
pushButtonData.ToolTipImage = ToBitmapSource(toolTipImage);
return pushButtonData;
}
/// <summary>
/// 通过判断keyTip来区分原始Tab与插件Tab然后切换插件Tab的可见性
/// </summary>
/// <param name="tabName"></param>
public static void SetVisible(string tabName)
{
var ribbonControl = adWin.ComponentManager.Ribbon;
foreach (var tab in ribbonControl.Tabs)
{
if (!tab.IsContextualTab && !tab.IsMergedContextualTab && tab.KeyTip == null && tabName == tab.Name)
{
tab.IsVisible = !tab.IsVisible;
}
}
}
#region
/// <summary>
/// 新建命令按钮
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="text"></param>
/// <param name="image"></param>
/// <param name="largeImage"></param>
/// <param name="toolTip"></param>
/// <param name="longDescription"></param>
/// <returns></returns>
public static PushButtonData NewButtonData<T>(
string text,
Bitmap largeImage = null,
Bitmap image = null,
string toolTip = null,
string longDescription = null
)
where T : class, IExternalCommand
{
return new(typeof(T).FullName, text, AddInPath, typeof(T).FullName)
{
LargeImage = largeImage?.ToBitmapSource(),
Image = image?.ToBitmapSource(),
ToolTip = toolTip ?? text,
LongDescription = longDescription
};
}
/// <summary>
/// 新建可控的命令按钮
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="V"></typeparam>
/// <param name="text"></param>
/// <param name="bitmap"></param>
/// <param name="largeBitmap"></param>
/// <param name="toolTip"></param>
/// <param name="longDescription"></param>
/// <returns></returns>
public static PushButtonData NewButtonData<T, V>(
string text,
Bitmap largeBitmap = null,
Bitmap bitmap = null,
string toolTip = null,
string longDescription = null
)
where T : class, IExternalCommand
where V : class, IExternalCommandAvailability
{
return new(typeof(T).FullName, text, AddInPath, typeof(T).FullName)
{
LargeImage = largeBitmap?.ToBitmapSource(),
Image = bitmap?.ToBitmapSource(),
ToolTip = toolTip ?? text,
LongDescription = longDescription,
AvailabilityClassName = typeof(V).FullName
};
}
#endregion
}