Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
<PackageReference Include="Nice3point.Revit.Build.Tasks" Version="3.0.1" PrivateAssets="all"/>
<PackageReference Include="Nice3point.Revit.Api.AdWindows" Version="$(RevitVersion).*" PrivateAssets="all"/>
<PackageReference Include="Nice3point.Revit.Api.RevitAPI" Version="$(RevitVersion).*" PrivateAssets="all"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
using System.Reflection;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI;
using Autodesk.Windows;
using System.Reflection;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using UIFramework;
using UIFrameworkServices;
using RibbonItem = Autodesk.Revit.UI.RibbonItem;
using RibbonPanel = Autodesk.Revit.UI.RibbonPanel;
#if REVIT2024_OR_GREATER
using System.ComponentModel;
using System.IO;
using System.Windows.Media.Imaging;
using RibbonButton = Autodesk.Revit.UI.RibbonButton;
#endif

Expand Down Expand Up @@ -128,6 +131,21 @@ private static Autodesk.Windows.RibbonPanel GetInternalPanel(this RibbonPanel pa
return (Autodesk.Windows.RibbonPanel)internalField.GetValue(panel)!;
}

/// <summary>
/// Converts a <see cref="System.Drawing.Bitmap"/> into a WPF-compatible <see cref="BitmapSource"/>.
/// </summary>
/// <param name="bitmap">The GDI+ <see cref="System.Drawing.Bitmap"/> to convert.</param>
/// <returns>A <see cref="BitmapSource"/> that can be assigned to WPF image properties (e.g., Ribbon button images).</returns>
/// <remarks>
/// The created <see cref="BitmapSource"/> holds a handle (HBITMAP) allocated by GDI. If the source bitmap is created at runtime
/// and not needed afterwards, ensure it is properly disposed. The unmanaged HBITMAP returned by <c>GetHbitmap()</c> is released
/// by the WPF imaging subsystem when the <see cref="BitmapSource"/> is garbage collected.
/// </remarks>
private static BitmapSource ConvertToImageSource(System.Drawing.Bitmap bitmap)
{
return Imaging.CreateBitmapSourceFromHBitmap(bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
}

#if REVIT2024_OR_GREATER
/// <summary>
/// Monitors the button for theme changes and updates the image accordingly.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -568,6 +568,29 @@ public static RibbonButton SetImage(this RibbonButton button, string uri)
return button;
}

/// <summary>
/// Sets a 16x16 pixel, 96dpi image for the given Ribbon button using an in-memory <see cref="System.Drawing.Bitmap"/>.
/// </summary>
/// <param name="button">The Ribbon button to which the image will be applied.</param>
/// <param name="bitmap">The bitmap representing the icon (ideally 16x16 at 96 dpi; larger images will be scaled by Revit/WPF).</param>
/// <returns>The Ribbon button with the applied image.</returns>
/// <remarks>
/// Use this overload when the icon is produced at runtime or loaded from a stream/embedded resource, instead of referencing it via a pack or file URI. The bitmap is converted internally to a WPF ImageSource.
/// </remarks>
/// <example>
/// <code>
/// using (var bmp = new System.Drawing.Bitmap(resourceStream))
/// {
/// pushButton.SetImage(bmp);
/// }
/// </code>
/// </example>
public static RibbonButton SetImage(this RibbonButton button, System.Drawing.Bitmap bitmap)
{
button.Image = ConvertToImageSource(bitmap);
return button;
}

/// <summary>
/// Sets a 32x32 pixel, 96dpi image from the specified URI source to the given Ribbon button.
/// </summary>
Expand All @@ -592,6 +615,29 @@ public static RibbonButton SetLargeImage(this RibbonButton button, string uri)
return button;
}

/// <summary>
/// Sets a 32x32 pixel, 96dpi image for the given Ribbon button using an in-memory <see cref="System.Drawing.Bitmap"/>.
/// </summary>
/// <param name="button">The Ribbon button to which the large image will be applied.</param>
/// <param name="bitmap">The bitmap representing the icon (ideally 32x32 at 96 dpi; larger images will be scaled by Revit/WPF).</param>
/// <returns>The Ribbon button with the applied large image.</returns>
/// <remarks>
/// Use this overload when the large icon is produced at runtime or loaded from a stream/embedded resource, instead of referencing it via a pack or file URI. The bitmap is converted internally to a WPF ImageSource in a memory-efficient way.
/// </remarks>
/// <example>
/// <code>
/// using (var bmp = new System.Drawing.Bitmap(resourceStream))
/// {
/// pushButton.SetLargeImage(bmp);
/// }
/// </code>
/// </example>
public static RibbonButton SetLargeImage(this RibbonButton button, System.Drawing.Bitmap bitmap)
{
button.LargeImage = ConvertToImageSource(bitmap);
return button;
}

/// <summary>
/// Sets the availability controller class for a PushButton.
/// This class determines when the PushButton will be enabled or disabled in the Revit UI.
Expand Down Expand Up @@ -681,4 +727,25 @@ public static RibbonItem SetLongDescription(this RibbonItem button, string descr
button.LongDescription = description;
return button;
}

/// <summary>
/// Sets contextual help for the specified <see cref="RibbonItem"/> using a URL.
/// </summary>
/// <param name="button">The <see cref="RibbonItem"/> to which contextual help will be assigned.</param>
/// <param name="helpPath">A URL pointing to online help content (e.g., documentation, knowledge base, or support page).</param>
/// <returns>The same <see cref="RibbonItem"/> instance with contextual help configured.</returns>
/// <remarks>
/// Contextual help is displayed when the user clicks the help button (question mark) in the extended tooltip.
/// Only URL-based help is supported by this helper method. If you need to use other help types (e.g., chm / context id), create a <see cref="ContextualHelp"/> instance manually and call Revit's native SetContextualHelp method.
/// </remarks>
/// <example>
/// <code>
/// button.SetContextualHelp("https://mydomain.com/docs/command-help");
/// </code>
/// </example>
public static RibbonItem SetContextualHelp(this RibbonItem button, string helpPath)
{
button.SetContextualHelp(new ContextualHelp(ContextualHelpType.Url, helpPath));
return button;
}
}