Hi Sham,
Yes, you can do what you require from an Excel-DNA add-in.
Here is some step-by-step guide on getting started with the Ribbon:
Tutorials/Fundamentals/RibbonBasics at master · Excel-DNA/Tutorials (github.com)
Now to do the kind of update you are asking about, you would do the following:
ExcelAsyncUtil.QueueAsMacro(() => _ribbonUI.InvalidateControl("loginIndicator"));
You can also search for these keywords to find further discussion and examples on the Google group: “onload”, “Invalidate”, “QueueAsMacro”.
-Govert
--
You received this message because you are subscribed to the Google Groups "Excel-DNA" group.
To unsubscribe from this group and stop receiving emails from it, send an email to exceldna+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/exceldna/ee0275f9-46f3-43c9-bc94-4e33759df3a0n%40googlegroups.com.
Hi Govert,
While implementing functionality in our Excel add-in, I encountered an error when attempting to add a custom image to the GetButtonImage method. Specifically, I received the following error messages:
This error does not occur when using inbuilt images (imageMso), but it persists when attempting to add custom images.
Additionally, I would like to mention that I have successfully implemented functionality to update the Ribbon icon based on login status. However, I am encountering difficulty when trying to update a custom image in the Ribbon.
Could you kindly provide insights into the possible reasons for this issue or suggest steps to resolve it? I have reviewed the code and ensured that the image path is correctly specified, but the error persists.
Please refer below code for clear understanding.
Ribboncontroller.cs file -
using ExcelDna.Integration.CustomUI;
using ExcelDna.Integration;
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Net;
using Newtonsoft.Json;
using System.Timers;
namespace BanorCapital
{
[ComVisible(true)]
public partial class RibbonController : ExcelRibbon, IDisposable
{
private Microsoft.Office.Core.IRibbonUI _ribbonUi;
private string selectedDataSource = "Influx";
private static RibbonController instance;
private bool isFlagEnabled = false;
string username = "a.pagare";
private System.Timers.Timer timer;
public static RibbonController Instance
{
get { return instance; }
}
public string SelectedDataSource
{
get { return selectedDataSource; }
set { selectedDataSource = value; }
}
/// <summary>
/// Gets the Excel application instance.
/// </summary>
private Microsoft.Office.Interop.Excel.Application App
{
get => (Microsoft.Office.Interop.Excel.Application)ExcelDnaUtil.Application;
}
/// <summary>
/// Handles the Ribbon load event.
/// Initializes the IRibbonUI interface.
/// </summary>
public void OnLoad(Microsoft.Office.Core.IRibbonUI ribbonUI)
{
_ribbonUi = ribbonUI;
instance = this; // Assign the current instance to the static property
}
/// <summary>
/// Handles the "Settings" button click on the Ribbon.
/// Displays the login form if the user is not already authenticated.
/// </summary>
public void OnSettings(Microsoft.Office.Core.IRibbonControl control)
{
if (IsUserAuthenticated())
{
MessageBox.Show("You are already logged in.", "Already Logged In", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
if (!IsUserAuthenticated())
{
var loginForm = new LoginForm();
DialogResult result = loginForm.ShowDialog();
if (result != DialogResult.OK)
{
return;
}
}
}
/// <summary>
/// Checks if the user is authenticated.
/// </summary>
/// <returns>True if the user is authenticated, otherwise false.</returns>
private bool IsUserAuthenticated()
{
return LoginForm.IsAuthenticated;
}
/// <summary>
/// Handles the "All Funds" button click on the Ribbon.
/// Displays a pop-up with information about all available funds.
/// </summary>
public void OnAllFunds(Microsoft.Office.Core.IRibbonControl control)
{
//As per client requirement need to disable authinticate functionality.
//if (!LoginForm.IsAuthenticated)
//{
// MessageBox.Show("You must be logged in to access this functionality.", "Access Denied", MessageBoxButtons.OK, MessageBoxIcon.Warning);
// return; // Exit the method since the user is not authenticated
//}
ShowAllFundsPopup();
}
/// <summary>
/// Handles the "Available Fields" button click on the Ribbon.
/// Displays a pop-up with information about available fields.
/// </summary>
public void OnAvailableFields(Microsoft.Office.Core.IRibbonControl control)
{
//As per client requirement need to disable authinticate functionality.
//if (!LoginForm.IsAuthenticated)
//{
// MessageBox.Show("You must be logged in to access this functionality.", "Access Denied", MessageBoxButtons.OK, MessageBoxIcon.Warning);
// return;
//}
var popup = new AvailableFieldsPopup();
popup.ShowDialog();
}
/// <summary>
/// Handles the "Show Version" button click on the Ribbon.
/// Displays the add-in version information.
/// </summary>
public void OnShowVersion(Microsoft.Office.Core.IRibbonControl control)
{
const string projectVersion = "1.0.2";
MessageBox.Show($"BanorCapital Add-In Version: {projectVersion}", "", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
/// <summary>
/// Handles the "User Manual" button click on the Ribbon.
/// Displays the user manual form.
/// </summary>
public void OnUserManual(Microsoft.Office.Core.IRibbonControl control)
{
var userManualForm = new UserManualForm();
userManualForm.ShowDialog();
}
public void ToggleFlagAndIcon()
{
isFlagEnabled = !isFlagEnabled; // Toggle the flag
}
public void OnToggleButton(Microsoft.Office.Core.IRibbonControl control)
{
ToggleFlagAndIcon(); // Toggle the flag and update the image
}
public RibbonController()
{
// Initialize timer with 10 seconds interval
timer = new System.Timers.Timer(10000);
timer.Elapsed += Timer_Elapsed;
timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
// Call GetButtonImage to update the button image
_ribbonUi.InvalidateControl("toggle_button");
}
public string GetButtonImage(Microsoft.Office.Core.IRibbonControl control)
{
bool flagStatus = FetchFlagStatusFromEndpoint(username);
// bool flagStatus = false;
return flagStatus ? "PersonaStatusOnline" : "InkToolsClose";
//return !isFlagEnabled ? "ToggleImage" : "SQLIcon";
}
private bool FetchFlagStatusFromEndpoint(string username)
{
string endpointUrl = $"http://172.16.5.21:5027/get-isuseractive/{username}";
try
{
using (var client = new WebClient())
{
string jsonResponse = client.DownloadString(endpointUrl);
dynamic responseData = JsonConvert.DeserializeObject(jsonResponse);
bool flagStatus = responseData.flagStatus;
isFlagEnabled = flagStatus;
_ribbonUi.InvalidateControl("toggle_button");
return flagStatus;
}
}
catch (WebException ex)
{
Console.WriteLine($"Error fetching flag status: {ex.Message}");
throw ex;
}
catch (JsonException ex)
{
Console.WriteLine($"Error parsing JSON response: {ex.Message}");
throw ex;
}
}
/// <summary>
/// Disposes of resources used by the RibbonController.
/// </summary>
public void Dispose()
{
}
}
}
.dna file -
<?xml version="1.0" encoding="utf-8"?>
<DnaLibrary Name="BanorCapital Add-In" RuntimeVersion="v4.0" xmlns="http://schemas.excel-dna.net/addin/2020/07/dnalibrary">
<ExternalLibrary Path="BanorCapital.dll" ExplicitExports="false" LoadFromBytes="true" Pack="true" IncludePdb="false" />
<CustomUI>
<customUI xmlns='http://schemas.microsoft.com/office/2009/07/customui' loadImage='LoadImage' onLoad='OnLoad'>
<ribbon>
<tabs>
<tab id='sample_tab' label='Banorcapital'>
<group id='sample_group' label='Operations'>
<button id='all_funds' label='Fund List' size='large' onAction='OnAllFunds' image='AllFunds'/>
<button id='fetch_data' label='Portfolio Data' size='large' onAction='OnFetchData' image='PortFolio'/>
<button id='available_fields' label='Available Fields' size='large' onAction='OnAvailableFields' image='CustomAvailableFields'/>
</group>
<group id='database_group' label='Data Sources'>
<checkBox id='checkbox_sql' label='SQL'
onAction='OnCheckBoxSql'
getPressed='GetCheckBoxSqlPressed'
screentip='Select SQL data source'
supertip='Select this option to fetch data from an SQL database'/>
<checkBox id='checkbox_influx' label='Influx'
onAction='OnCheckBoxInflux'
getPressed='GetCheckBoxInfluxPressed'
screentip='Select InfluxDB data source'
supertip='Select this option to fetch data from InfluxDB'/>
<checkBox id='checkbox_bpipe' label='B-Pipe'
onAction='OnCheckBoxBPipe'
getPressed='GetCheckBoxBPipePressed'
screentip='Select B Pipe data source'
supertip='Select this option to fetch data from B Pipe'/>
</group>
<group id='dynamic_group' label='B-Pipe App'>
<button id='toggle_button' label='Status' size='large' onAction='OnToggleButton' getImage='GetButtonImage'/>
</group>
<group id='setting_group' label='Settings'>
<button id='settings_button' label='Settings' size='large' onAction='OnSettings' image='Settings'/>
</group>
<group id='info_group' label='Info'>
<button id='user_manual_button' label='Help' size='large' onAction='OnUserManual' image='UserManual'/>
<button id='version_button' label='Version' size='large' onAction='OnShowVersion' image='VersionIcon'/>
</group>
</tab>
</tabs>
</ribbon>
</customUI>
</CustomUI>
<Image Name='PortFolio' Path='Images\PortFolio.png' Pack='true' />
<Image Name='CustomAvailableFields' Path='Images\AvailableFields.png' Pack='true' />
<Image Name='AllFunds' Path='Images\AllFunds.png' Pack='true' />
<Image Name='Settings' Path='Images\Settings.png' Pack='true' />
<Image Name='VersionIcon' Path='Images\VersionIcon.png' Pack='true' />
<Image Name='UserManual' Path='Images\UserManual.png' Pack='true' />
<Image Name='ToggleImage' Path='Images\ToggleImage.png' Pack='true' />
<Image Name='SQLIcon' Path='Images\SQLIcon.png' Pack='true' />
</DnaLibrary>
Hi Govert,
Thanks for the clarification!
I've updated the getImage callback method according to your guidance, and it's now working smoothly with both custom and built-in images.
Best regards, Sham