Files
ShrlAlgoToolkit/ShrlAlgoToolkit.Revit/Extensions/UIExtensions.cs

617 lines
20 KiB
C#
Raw Normal View History

2025-04-24 20:56:44 +08:00

using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using ShrlAlgoToolkit.Core.Assists;
using System.Diagnostics;
2024-09-22 11:05:41 +08:00
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
2025-04-24 20:56:44 +08:00
using System.Windows;
2024-10-08 16:21:39 +08:00
using System.Windows.Input;
2025-04-24 20:56:44 +08:00
using System.Windows.Interop;
2024-09-22 11:05:41 +08:00
using System.Windows.Media.Imaging;
2025-04-24 20:56:44 +08:00
using adWin = Autodesk.Windows;
2024-09-22 11:05:41 +08:00
2025-04-24 20:56:44 +08:00
namespace ShrlAlgoToolkit.Revit.Assists;
2024-09-22 11:05:41 +08:00
2025-04-24 20:56:44 +08:00
public static class UIExtensions
2024-09-22 11:05:41 +08:00
{
2024-10-08 16:21:39 +08:00
/// <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
);
2024-09-22 11:05:41 +08:00
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
private static extern bool SetWindowText(IntPtr hWnd, string lpString);
2024-10-08 16:21:39 +08:00
/// <summary>
/// 面板上添加项
/// </summary>
/// <param name="panel"></param>
/// <param name="item"></param>
public static void AddAwItem(this adWin.RibbonPanel panel, adWin.RibbonItem item)
2024-09-22 11:05:41 +08:00
{
2024-10-08 16:21:39 +08:00
panel.Source.Items.Add(item);
2024-09-22 11:05:41 +08:00
}
2024-10-08 16:21:39 +08:00
/// <summary>
/// 添加堆叠按钮组
/// </summary>
/// <param name="rowPanel"></param>
/// <param name="ribbonButtons"></param>
public static void AddAwStackItems(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());
}
}
}
2024-09-22 11:05:41 +08:00
/// <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>
/// 创建一个下拉式按钮。
/// </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="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;
}
2024-10-08 16:21:39 +08:00
2024-09-22 11:05:41 +08:00
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;
}
2024-10-08 16:21:39 +08:00
/// <summary>
/// 在Revit现有的标签下如不存在则创建创建创建面板
/// </summary>
/// <param name="application"></param>
/// <param name="panelName">创建的面板名称</param>
/// <param name="tabName">若Tab不存在则创建对应名称的Tab</param>
/// <returns></returns>
public static RibbonPanel AddUIPanel(this UIControlledApplication application, string tabName, string panelName)
{
var ribbonTab = adWin.ComponentManager.Ribbon.Tabs.FirstOrDefault(tab => tab.Id.Equals(tabName));
if (ribbonTab == 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);
}
2024-09-22 11:05:41 +08:00
2024-10-08 16:21:39 +08:00
public static adWin.RibbonItem ConvertToAwRibbonItem(this RibbonButton btn)
2024-09-22 11:05:41 +08:00
{
2024-10-08 16:21:39 +08:00
return (adWin.RibbonItem)btn.GetType()
.InvokeMember(
"getRibbonItem",
BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod,
Type.DefaultBinder,
btn,
null
);
2024-09-22 11:05:41 +08:00
}
/// <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);
}
2024-10-08 16:21:39 +08:00
2024-09-22 11:05:41 +08:00
/// <summary>
2024-10-08 16:21:39 +08:00
/// 查找面板
2024-09-22 11:05:41 +08:00
/// </summary>
2024-10-08 16:21:39 +08:00
/// <param name="rt"></param>
/// <param name="panelName"></param>
2024-09-22 11:05:41 +08:00
/// <returns></returns>
2024-10-08 16:21:39 +08:00
public static adWin.RibbonPanel FindAwPanel(this adWin.RibbonTab rt, string panelName)
{
return rt.Panels.FirstOrDefault(p => p.Source.Name == panelName);
}
/// <summary>
/// 查找Tab
/// </summary>
/// <param name="tabName">标签名</param>
/// <returns></returns>
public static adWin.RibbonTab FindAwTab(string tabName)
{
return adWin.ComponentManager.Ribbon.Tabs.FirstOrDefault(tab => tab.Id.Equals(tabName));
}
2024-09-22 11:05:41 +08:00
public static ToggleButton GetToggleButton(this RadioButtonGroup radioButtonGroup)
{
return radioButtonGroup.Current;
}
2025-04-24 20:56:44 +08:00
2024-09-22 11:05:41 +08:00
/// <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;
}
2024-10-08 16:21:39 +08:00
/// <summary>
/// 设置按钮可用性
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="pushButtonData"></param>
/// <returns></returns>
2024-09-22 11:05:41 +08:00
public static PushButtonData SetAvailability<T>(this PushButtonData pushButtonData)
where T : IExternalCommandAvailability
{
pushButtonData.AvailabilityClassName = typeof(T).FullName;
return pushButtonData;
}
2024-10-08 16:21:39 +08:00
/// <summary>
/// 设置面板右下角箭头对话框
/// </summary>
public static void SetAwDialogLauncher(this adWin.RibbonPanel panel, adWin.RibbonCommandItem item)
{
if (panel != null)
{
panel.Source.DialogLauncher = item;
}
}
public static adWin.RibbonItem SetAwImage(this adWin.RibbonItem ribbonItem, Bitmap image)
{
2025-04-24 20:56:44 +08:00
ribbonItem.Image = ToBitmapSource(image);
2024-10-08 16:21:39 +08:00
return ribbonItem;
}
public static void SetAwImage(this adWin.RibbonItem ribbonItem, string uri)
{
ribbonItem.Image = new BitmapImage(new Uri(uri, UriKind.RelativeOrAbsolute));
}
public static adWin.RibbonItem SetAwLargeImage(this adWin.RibbonItem ribbonItem, Bitmap largeImage)
{
2025-04-24 20:56:44 +08:00
ribbonItem.LargeImage = ToBitmapSource(largeImage);
2024-10-08 16:21:39 +08:00
return ribbonItem;
}
2024-09-22 11:05:41 +08:00
/// <summary>
2024-10-08 16:21:39 +08:00
/// 从 URI 源添加 32x32px-96dpi 图像
2024-09-22 11:05:41 +08:00
/// </summary>
2024-10-08 16:21:39 +08:00
/// <param name="button">添加图标的按钮</param>
/// <param name="uri">图标的相对或绝对路径</param>
/// <example>button.SetAwLargeImage("/RevitAddIn;component/Resources/Icons/RibbonIcon32.png")</example>
public static void SetAwLargeImage(this adWin.RibbonItem ribbonItem, string uri)
{
ribbonItem.LargeImage = new BitmapImage(new Uri(uri, UriKind.RelativeOrAbsolute));
}
public static adWin.RibbonItem SetAwShowText(this adWin.RibbonItem ribbonItem, string text)
2024-09-22 11:05:41 +08:00
{
2024-10-08 16:21:39 +08:00
ribbonItem.Text = text;
return ribbonItem;
}
public static adWin.RibbonItem SetAwToolTip(this adWin.RibbonItem ribbonItem, string tooltip)
{
ribbonItem.ToolTip = tooltip;
return ribbonItem;
2024-09-22 11:05:41 +08:00
}
public static PushButtonData SetDescription(this PushButtonData pushButtonData, string longDescription)
{
pushButtonData.LongDescription = longDescription;
return pushButtonData;
}
/// <summary>
2024-10-08 16:21:39 +08:00
/// 设置面板右下角箭头对话框
2024-09-22 11:05:41 +08:00
/// </summary>
2024-10-08 16:21:39 +08:00
public static void SetDialogLauncher(string tabName, string panelName)
2024-09-22 11:05:41 +08:00
{
var group = adWin.ComponentManager.Ribbon.Tabs
2024-10-08 16:21:39 +08:00
.FirstOrDefault(tab => tab.Name == tabName)
.Panels.FirstOrDefault(p => p.AutomationName == panelName) ?? throw new ArgumentException("未找到标签或面板");
group.Source.DialogLauncher = group.Source.Items.First() as adWin.RibbonCommandItem;
2024-09-22 11:05:41 +08:00
}
/// <summary>
2024-10-08 16:21:39 +08:00
/// 设置面板右下角箭头对话框
2024-09-22 11:05:41 +08:00
/// </summary>
2024-10-08 16:21:39 +08:00
public static void SetDialogLauncher(adWin.RibbonTab tab, string panelName)
2024-09-22 11:05:41 +08:00
{
2024-10-08 16:21:39 +08:00
var group = tab.Panels.FirstOrDefault(p => p.AutomationName == panelName) ?? throw new ArgumentException("未找到标签或面板");
group.Source.DialogLauncher = group.Source.Items.First() as adWin.RibbonCommandItem;
2024-09-22 11:05:41 +08:00
}
2024-10-08 16:21:39 +08:00
2024-09-22 11:05:41 +08:00
/// <summary>
/// 双击选项
/// </summary>
public static void SetDoubleClickAction(DoubleClickTarget target, DoubleClickAction clickAction)
{
var doubleOpt = DoubleClickOptions.GetDoubleClickOptions();
//DoubleClickAction dca = doubleOpt.GetAction(DoubleClickTarget.Family);
doubleOpt.SetAction(target, clickAction);
}
2024-10-08 16:21:39 +08:00
2024-09-22 11:05:41 +08:00
/// <summary>
/// 提示包含短视频
/// </summary>
/// <param name="pushButtonData"></param>
/// <param name="title"></param>
2024-10-08 16:21:39 +08:00
/// <param name="videoPath">视频路径</param>
2024-09-22 11:05:41 +08:00
public static void SetExpandedVideo(this PushButtonData pushButtonData, string title, string videoPath)
{
2024-10-08 16:21:39 +08:00
//拿到Autodesk.Windows的RibbonItem转换
2024-09-22 11:05:41 +08:00
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) };
}
}
2024-10-08 16:21:39 +08:00
/// <summary>
/// 设置16x16的小图片
/// </summary>
/// <param name="pushButtonData"></param>
/// <param name="image"></param>
/// <returns></returns>
2024-09-22 11:05:41 +08:00
public static PushButtonData SetImage(this PushButtonData pushButtonData, Bitmap image)
{
2025-04-24 20:56:44 +08:00
pushButtonData.Image = ToBitmapSource(image);
2024-09-22 11:05:41 +08:00
return pushButtonData;
}
2024-10-08 16:21:39 +08:00
/// <summary>
/// 使用Uri设置16x16的小图片
/// </summary>
/// <param name="pushButtonData"></param>
/// <param name="uri"></param>
public static PushButtonData SetImage(this PushButtonData pushButtonData, string uri)
2024-09-22 11:05:41 +08:00
{
2024-10-08 16:21:39 +08:00
pushButtonData.Image = new BitmapImage(new Uri(uri, UriKind.RelativeOrAbsolute));
return pushButtonData;
2024-09-22 11:05:41 +08:00
}
2024-10-08 16:21:39 +08:00
2024-09-22 11:05:41 +08:00
/// <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);
}
2024-10-08 16:21:39 +08:00
/// <summary>
/// 设置32x32-96dpi的大图片
/// </summary>
/// <param name="pushButtonData"></param>
/// <param name="largeImage"></param>
/// <returns></returns>
2024-09-22 11:05:41 +08:00
public static PushButtonData SetLargeImage(this PushButtonData pushButtonData, Bitmap largeImage)
{
2025-04-24 20:56:44 +08:00
pushButtonData.LargeImage = ToBitmapSource(largeImage);
2024-09-22 11:05:41 +08:00
return pushButtonData;
}
/// <summary>
2024-10-08 16:21:39 +08:00
/// 从 URI 源添加 32x32px-96dpi 图像
2024-09-22 11:05:41 +08:00
/// </summary>
2024-10-08 16:21:39 +08:00
/// <param name="pushButtonData">添加图标的按钮</param>
/// <param name="uri">图标的相对或绝对路径</param>
/// <example>button.SetAwLargeImage("/RevitAddIn;component/Resources/Icons/RibbonIcon32.png")</example>
public static void SetLargeImage(this PushButtonData pushButtonData, string uri)
2024-09-22 11:05:41 +08:00
{
2024-10-08 16:21:39 +08:00
pushButtonData.LargeImage = new BitmapImage(new Uri(uri, UriKind.RelativeOrAbsolute));
2024-09-22 11:05:41 +08:00
}
2024-10-08 16:21:39 +08:00
2024-09-22 11:05:41 +08:00
/// <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>
2024-10-08 16:21:39 +08:00
/// 设置显示文字
2024-09-22 11:05:41 +08:00
/// </summary>
2024-10-08 16:21:39 +08:00
/// <param name="pushButtonData"></param>
/// <param name="text"></param>
2024-09-22 11:05:41 +08:00
/// <returns></returns>
public static PushButtonData SetShowText(this PushButtonData pushButtonData, string text)
{
pushButtonData.Text = text;
return pushButtonData;
}
2024-10-08 16:21:39 +08:00
/// <summary>
/// 设置工具提示
/// </summary>
/// <param name="pushButtonData"></param>
/// <param name="tooltip"></param>
/// <returns></returns>
2024-09-22 11:05:41 +08:00
public static PushButtonData SetToolTip(this PushButtonData pushButtonData, string tooltip)
{
pushButtonData.ToolTip = tooltip;
return pushButtonData;
}
2024-10-08 16:21:39 +08:00
/// <summary>
/// 设置工具提示图片
/// </summary>
/// <param name="pushButtonData"></param>
/// <param name="toolTipImage"></param>
/// <returns></returns>
2024-09-22 11:05:41 +08:00
public static PushButtonData SetToolTipImage(this PushButtonData pushButtonData, Bitmap toolTipImage)
{
2025-04-24 20:56:44 +08:00
pushButtonData.ToolTipImage = ToBitmapSource(toolTipImage);
2024-09-22 11:05:41 +08:00
return pushButtonData;
}
2025-04-24 20:56:44 +08:00
/// <summary>
/// 位图转像素集
/// </summary>
/// <param name="bitmap"></param>
/// <returns></returns>
private static BitmapSource ToBitmapSource(Bitmap bitmap)
{
return bitmap == null
? null
: Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}
2024-09-22 11:05:41 +08:00
/// <summary>
/// 通过判断keyTip来区分原始Tab与插件Tab然后切换插件Tab的可见性
/// </summary>
/// <param name="tabName"></param>
2024-10-08 16:21:39 +08:00
/// <param name="visible"></param>
public static void SetVisible(string tabName, bool visible)
2024-09-22 11:05:41 +08:00
{
var ribbonControl = adWin.ComponentManager.Ribbon;
2024-10-08 16:21:39 +08:00
var tab = ribbonControl.Tabs
.FirstOrDefault(
tab => !tab.IsContextualTab &&
!tab.IsMergedContextualTab &&
tab.KeyTip == null &&
tabName == tab.Name);
if (tab != null)
2024-09-22 11:05:41 +08:00
{
2024-10-08 16:21:39 +08:00
tab.IsVisible = visible;
2024-09-22 11:05:41 +08:00
}
}
2024-10-08 16:21:39 +08:00
2024-09-22 11:05:41 +08:00
}