diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 0000000..d4d7895 --- /dev/null +++ b/CHANGES.md @@ -0,0 +1 @@ +See: https://github.com/caioproiete/serilog-sinks-exceldnalogdisplay/releases diff --git a/README.md b/README.md index 279195a..16fa792 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,109 @@ -# Serilog.Sinks.ExcelDnaLogDisplay +# Serilog.Sinks.ExcelDnaLogDisplay [![NuGet Version](http://img.shields.io/nuget/v/Serilog.Sinks.ExcelDnaLogDisplay.svg?style=flat)](https://www.nuget.org/packages/Serilog.Sinks.ExcelDnaLogDisplay/) [![License](https://img.shields.io/github/license/caioproiete/serilog-sinks-exceldnalogdisplay.svg)](LICENSE) -Writes [Serilog](https://serilog.net) events to [Excel-DNA](https://excel-dna.net) LogDisplay. +Writes [Serilog](https://serilog.net) events to [Excel-DNA](https://excel-dna.net) `LogDisplay`. ![Excel-DNA LogDisplay window screenshot](assets/exceldna-logdisplay-window.png) +### Getting started + +Install the [Serilog.Sinks.ExcelDnaLogDisplay](https://www.nuget.org/packages/Serilog.Sinks.ExcelDnaLogDisplay/) package from NuGet: + +```powershell +Install-Package Serilog.Sinks.ExcelDnaLogDisplay +``` + +To configure the sink in C# code, call `WriteTo.ExcelDnaLogDisplay()` during logger configuration: + +```csharp +var log = new LoggerConfiguration() + .WriteTo.ExcelDnaLogDisplay(displayOrder: DisplayOrder.NewestFirst) + .CreateLogger(); +``` +### Example of an Excel-DNA add-in using Serilog with this sink + +In the [sample](sample/) folder, there's an example of an Excel-DNA add-in that uses Serilog for logging to the `LogDisplay` of Excel-DNA using this sink, from different contexts, suchs as from an `ExcelRibbon` control event handler as well from an `ExcelFunction`: + +[![Excel-DNA LogDisplay sample add-in ribbon screenshot](assets/sample-addin-ribbon.png)](sample/SampleAddIn/Ribbon.cs) + +[![Excel-DNA LogDisplay sample add-in Excel function screenshot](assets/sample-addin-function.png)](sample/SampleAddIn/Functions.cs) + +### XML `` configuration + +To use the Excel-DNA LogDisplay sink with the [Serilog.Settings.AppSettings](https://github.com/serilog/serilog-settings-appsettings) package, first install that package if you haven't already done so: + +```powershell +Install-Package Serilog.Settings.AppSettings +``` + +Instead of configuring the logger in code, call `ReadFrom.AppSettings()`: + +```csharp +var log = new LoggerConfiguration() + .ReadFrom.AppSettings() + .CreateLogger(); +``` + +In your Excel-DNA Add-In's `App.config`, specify the Excel-DNA LogDisplay sink assembly under the `` node: + +```xml + + + + +``` + +The parameters that can be set through the `serilog:write-to:ExcelDnaLogDisplay` keys are the method parameters accepted by the `WriteTo.ExcelDnaLogDisplay()` configuration method. This means, for example, that the `displayOrder` parameter can be set with: + +```xml + +``` + +### Controlling event formatting + +The Excel-DNA LogDisplay sink creates events in a fixed text format by default: + +``` +2018-09-07 09:02:17.148 -03:00 [INF] HTTP GET / responded 200 in 1994 ms +``` + +The format is controlled using an _output template_, which the Excel-DNA LogDisplay sink configuration method accepts as an `outputTemplate` parameter. + +The default format above corresponds to an output template like: + +```csharp + .WriteTo.ExcelDnaLogDisplay( + outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}") +``` + +##### JSON event formatting + +To write events to the Excel-DNA LogDisplay in an alternative format such as [JSON](https://github.com/serilog/serilog-formatting-compact), pass an `ITextFormatter` as the first argument: + +```csharp + // Install-Package Serilog.Formatting.Compact + .WriteTo.ExcelDnaLogDisplay(new CompactJsonFormatter()) +``` + +### Auditing + +The Excel-DNA LogDisplay sink can operate as an audit sink through `AuditTo`: + +```csharp + .AuditTo.ExcelDnaLogDisplay(displayOrder: DisplayOrder.NewestFirst) +``` + +### Excel-DNA configuration for packing with `ExcelDnaPack` + +In order for the Excel-DNA LogDisplay sink to work from an add-in that was packaged using the ExcelDnaPack utility, you need to include references to `Serilog.dll` and `Serilog.Sinks.ExcelDnaLogDisplay.dll` in the `.dna` file of the add-in: + +```xml + + + + + +``` + --- _Copyright © 2018 Caio Proiete & Contributors - Provided under the [Apache License, Version 2.0](http://apache.org/licenses/LICENSE-2.0.html)._ diff --git a/assets/sample-addin-function.png b/assets/sample-addin-function.png new file mode 100644 index 0000000..dbb0f08 Binary files /dev/null and b/assets/sample-addin-function.png differ diff --git a/assets/sample-addin-ribbon.png b/assets/sample-addin-ribbon.png new file mode 100644 index 0000000..c30e364 Binary files /dev/null and b/assets/sample-addin-ribbon.png differ diff --git a/assets/serilog-sinks-exceldnalogdisplay-nuget.png b/assets/serilog-sinks-exceldnalogdisplay-nuget.png new file mode 100644 index 0000000..9e04299 Binary files /dev/null and b/assets/serilog-sinks-exceldnalogdisplay-nuget.png differ diff --git a/sample/SampleAddIn/AddIn.cs b/sample/SampleAddIn/AddIn.cs new file mode 100644 index 0000000..7c5ba64 --- /dev/null +++ b/sample/SampleAddIn/AddIn.cs @@ -0,0 +1,154 @@ +// Copyright 2018 Caio Proiete & Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Forms; +using ExcelDna.Integration; +using ExcelDna.Integration.Extensibility; +using ExcelDna.Logging; +using ExcelDna.Registration; +using Serilog; + +namespace SampleAddIn +{ + public class AddIn : ExcelComAddIn, IExcelAddIn + { + private static ILogger _log = Log.Logger; + + public void AutoOpen() + { + try + { + Application.ThreadException += ApplicationThreadUnhandledException; + AppDomain.CurrentDomain.UnhandledException += AppDomainUnhandledException; + TaskScheduler.UnobservedTaskException += TaskSchedulerUnobservedTaskException; + ExcelIntegration.RegisterUnhandledExceptionHandler(ExcelUnhandledException); + + _log = Log.Logger = ConfigureLogging(); + _log.Information("Starting sample Excel-DNA Add-In with Serilog Sink LogDisplay"); + + ExcelComAddInHelper.LoadComAddIn(this); + + _log.Verbose("Registering functions"); + + ExcelRegistration.GetExcelFunctions() + .Select(UpdateFunctionAttributes) + .RegisterFunctions(); + + _log.Information("Sample Excel-DNA Add-In with Serilog Sink LogDisplay started"); + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + } + + public void AutoClose() + { + // Do nothing + } + + public override void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom) + { + try + { + base.OnDisconnection(disconnectMode, ref custom); + + _log.Information("Stopping sample Excel-DNA Add-In with Serilog Sink LogDisplay"); + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + finally + { + _log.Information("Sample Excel-DNA Add-In with Serilog Sink LogDisplay stopped"); + + Log.CloseAndFlush(); + } + } + + public static void ProcessUnhandledException(Exception ex, string message = null, [CallerMemberName] string caller = null) + { + try + { + _log.Error(ex, message ?? $"Unhandled exception on {caller}"); + } + catch (Exception lex) + { + try + { + Serilog.Debugging.SelfLog.WriteLine(lex.ToString()); + } + catch + { + // Do nothing... + } + } + + if (ex.InnerException != null) + { + ProcessUnhandledException(ex.InnerException, message, caller); + return; + } + +#if DEBUG + MessageBox.Show(ex.ToString(), "Unexpected Error", MessageBoxButtons.OK, MessageBoxIcon.Error); +#else + const string errorMessage = "An unexpected error ocurred. Please try again in a few minutes, and if the error persists, contact support"; + MessageBox.Show(errorMessage, "Unexpected Error", MessageBoxButtons.OK, MessageBoxIcon.Error); +#endif + } + + private static ILogger ConfigureLogging() + { + return new LoggerConfiguration() + .MinimumLevel.Verbose() + .WriteTo.ExcelDnaLogDisplay(displayOrder: DisplayOrder.NewestFirst) + .CreateLogger(); + } + + private static ExcelFunctionRegistration UpdateFunctionAttributes(ExcelFunctionRegistration excelFunction) + { + excelFunction.FunctionAttribute.Name = excelFunction.FunctionAttribute.Name.ToUpperInvariant(); + return excelFunction; + } + + private static void ApplicationThreadUnhandledException(object sender, ThreadExceptionEventArgs e) + { + ProcessUnhandledException(e.Exception); + } + + private static void TaskSchedulerUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e) + { + ProcessUnhandledException(e.Exception); + e.SetObserved(); + } + + private static void AppDomainUnhandledException(object sender, UnhandledExceptionEventArgs e) + { + ProcessUnhandledException((Exception)e.ExceptionObject); + } + + private static object ExcelUnhandledException(object ex) + { + ProcessUnhandledException((Exception)ex); + return ex; + } + } +} diff --git a/sample/SampleAddIn/App.config b/sample/SampleAddIn/App.config new file mode 100644 index 0000000..781a3b8 --- /dev/null +++ b/sample/SampleAddIn/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/sample/SampleAddIn/Functions.cs b/sample/SampleAddIn/Functions.cs new file mode 100644 index 0000000..93f5f1a --- /dev/null +++ b/sample/SampleAddIn/Functions.cs @@ -0,0 +1,59 @@ +// Copyright 2018 Caio Proiete & Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using ExcelDna.Integration; +using Serilog; + +namespace SampleAddIn +{ + public static class Functions + { + private static readonly ILogger _log = Log.Logger.ForContext(typeof(Functions)); + + [ExcelFunction(Category = "Serilog", Description = "Writes a `Verbose` message to the LogDisplay via Serilog")] + public static string LogVerbose(string message) + { + _log.Verbose(message); + return $"'[VRB] {message}' written to the log"; + } + + [ExcelFunction(Category = "Serilog", Description = "Writes a `Debug` message to the LogDisplay via Serilog")] + public static string LogDebug(string message) + { + _log.Debug(message); + return $"'[DBG] {message}' written to the log"; + } + + [ExcelFunction(Category = "Serilog", Description = "Writes an `Information` message to the LogDisplay via Serilog")] + public static string LogInformation(string message) + { + _log.Information(message); + return $"'[INF] {message}' written to the log"; + } + + [ExcelFunction(Category = "Serilog", Description = "Writes a `Warning` message to the LogDisplay via Serilog")] + public static string LogWarning(string message) + { + _log.Warning(message); + return $"'[WRN] {message}' written to the log"; + } + + [ExcelFunction(Category = "Serilog", Description = "Writes an `Error` message to the LogDisplay via Serilog")] + public static string LogError(string message) + { + _log.Error(message); + return $"'[ERR] {message}' written to the log"; + } + } +} diff --git a/sample/SampleAddIn/OfficeCustomUI14.xsd b/sample/SampleAddIn/OfficeCustomUI14.xsd new file mode 100644 index 0000000..95ac40a --- /dev/null +++ b/sample/SampleAddIn/OfficeCustomUI14.xsd @@ -0,0 +1,3697 @@ + + + + + + ---------------------------------------------------------------------- + Schema definition for Ribbon Extensibility + ---------------------------------------------------------------------- + + + + + + ---------------------------------------------------------------------- + Attribute types + ---------------------------------------------------------------------- + + + + + + + + Specifies the "Qualified ID" for a built-in or custom control. + Custom controls can be given an idQ defined with a prefix, e.g. "myaddin:Save" + where "myaddin" must be an XML namespace defined in context of the element. + A qualified id allows multiple add-ins to refer to the same controls. + A custom control must have one of id, idQ, or idMso. + + + + + + + + + + + + + + Specifies the custom ID of a control. + + + + + + + + + + + + + + Specifies a unique ID. + + + + + + + + + + + + + + Specifies a delegate type which is used by a control to call back to a macro. + Callbacks are used to provide status, update properties or perform actions. + + + + + + + + + + + + + + Specifies a numeric argument which determines maximum string length, such as in editBox + String length is limited to 1024 characters. + + + + + + + + + + + + + + Specifies a numeric argument which determines maximum number of rows or columns in galleries. + + + + + + + + + + + + + + Specifies a numeric argument which determines maximum width or height of a gallery item. + + + + + + + + + + + + + Specifies the acceptable values for the gallery element's showInRibbon attribute. + + + + + + + + + + + + + Specifies a string argument. + String length is limited to 1024 characters. + + + + + + + + + + + + + + Specifies a string argument. + String length is limited to 4096 characters. + + + + + + + + + + + + + + Specifies a string argument which is a path to a file or a resource. + String length is limited to 1024 characters. + + + + + + + + + + + + + + Specifies the size of the button; "large" or "normal." + + + + + + + + + + + + + + Specifies the size of items in a menu; "normal" or "large". + + + + + + + + + + + + + + Style of a box control. "horizontal" or "vertical". + + + + + + + + + + + + + + Specifies a keytip. 1-3 characters, no whitespace. + + + + + + + + + + + + + + + Specifies the allowed sizes of task controls in taskGroups or taskFormGroups. + + + + + + + + + + + + + + + + ---------------------------------------------------------------------- + Attributes + ---------------------------------------------------------------------- + + + + + + + + Specifies attributes that specify custom control ID. + + + + + + + Specifies ID of a custom UI element. IDs must be unique across customUI XML file. + + + + + + + + A qualified control ID. + +To use a qualified name, you must first create your own namespace. The following code creates a namespace called myNameSpace, aliased by "x." + + <customUI xmlns="http://schemas.microsoft.com/office/2005/08/customui" xmlns:x="myNameSpace"> + +With this declaration, idQ is usable on controls: + + <group idQ="x:myButton" ... /> + +By creating a namespace x, two different add-ins can add to the same group, by referring to that custom group with its qualified name. + + + + + + + + Specifies custom data as string. + + + + + + + + + + Specifies ID of a built-in control. + + + + + + + Specifies ID of a built-in control. + + + + + + + + + + Specifies the title of a menu. + + + + + + + Title to show as a header when the menu is opened. + + + + + + + Callback for dynamically getting the title. + + + + + + + + + + Specifies attributes that specify control ID. + One of id, idMso, or idQ must be specified to identify a control. + + + + + + + + + + + + Specifies the control's image or icon. + Image attributes are mutually exclusive - only one of + "image", "imageMso", or "getImage" can be specified. + + + + + + + Specifies a custom image or icon. + + + + + + + Specifies an image or icon if a built-in control. + + + + + + + Specifies a callback which returns a custom image. + + + + + + + + + + Specifies attributes that can be applied to all commands and controls. + + + + + + + + + + + Specifies attributes that can determine position of an object within its container + (such as position of a control within a group or position of a tab relative to other tabs). + + + + + + + ID of built-in control to be inserted after. + Mutually exclusive with InsertBeforeMso, InsertAfterQ, InsertBeforeQ. + + + + + + + ID of built-in control to be inserted before. + Mutually exclusive with InsertAfterMso, InsertAfterQ, InsertBeforeQ. + + + + + + + ID of control to be inserted after. + Mutually exclusive with InsertAfterMso, InsertBeforeMso, InsertBeforeQ. + + + + + + + ID of control to be inserted before. + Mutually exclusive with InsertAfterMso, InsertBeforeMso, InsertAfterQ. + + + + + + + + + + Specifies attributes that can be applied to determine + if a control is enabled. + + + + + + + Specifies if a control is enabled. + + + + + + + Specifies a callback which returns true if control is enabled. + + + + + + + + + + Specifies attributes that can be applied to determine visibility. + + + + + + + Specifies if a control is visible. + + + + + + + Specifies a callback which returns true if control is visible. + + + + + + + + + + Specifies attributes that can be applied to determine the label. + + + + + + + Specifies the label. + + + + + + + Specifies a callback which returns custom label. + + + + + + + + + + Specifies attributes that can be applied to determine the Keytip. + + + + + + + Specifies the keytip. + + + + + + + Specifies a callback which returns custom keytip. + + + + + + + + + + Specifies attributes that can be applied to determine the screentip + to show when mouse is over the control. + + + + + + + Screentip to show when mouse is over the control. + + + + + + + Specifies a callback which returns the screentip. + + + + + + + Large screentip to show when mouse is over the control. + + + + + + + Specifies a callback which returns the Supertip. + + + + + + + + + + Specifies attributes that can be applied to determine the + extended description of the control, appears in menus with itemSize set to large. + + + + + + + Extended description of the control, appears in menus with itemSize set to large. + + + + + + + Specifies a callback which returns control description. + + + + + + + + + Specifies attributes that can be applied to specify the alternative + text of an image-based control. + + + + + + Alternative text for the control. + + + + + + + Specifies a callback which returns the alternative text. + + + + + + + + + + Specifies whether or not to show the label on a control. + + + + + + + Specifies a callback which returns whether to show the label. + + + + + + + + + Group HelperText + + + + + + + + + + + Specifies attributes that can be applied to all user interface items such as tabs and controls. + + + + + + + + + + + + + + + Specifies common attributes that can be applied to controls and groups. + + + + + + + + + + + + + Specifies attributes applied to controls. + + + + + + + + + Specifies whether or not to show the image on a control. + + + + + + + Specifies a callback which returns whether to show the image. + + + + + + + + + + Specifies an action callback. + + + + + + + Specifies a callback which responds on user action. + + + + + + + + + Specifies the GetPressed callback. + + + + + + Specifies a callback which returns true if the Button/CheckBox is pressed. + + + + + + + + + Specifies the isDefinitive attribute + + + + + + Specifies whether an action should close the Backstage when it is invoked + + + + + + + + + + Specifies a size attribute. + + + + + + + Specifies size of a button control. + + + + + + + Specifies a callback which returns a control's size. + + + + + + + + + + Specifies common attributes for controls with dropdowns (such as ComboBox or Gallery). + + + + + + + Specifies if the image is shown or hidden on dropdown items. + + + + + + + Specifies a callback which returns the number of items in dropdown. + + + + + + + Specifies a callback which returns the label for an item. + + + + + + + Specifies a callback which returns screentip for an item. + + + + + + + Specifies a callback which returns Supertip for an item. + + + + + + + Specifies a callback which returns the image for an item. + + + + + + + Specifies a callback which returns an ID for a dynamically generated item. + + + + + + + Specifies a representative string which should fit in the control. + E.g. if the control is meant for a credit card number a string of 16 digits + ensures appropriate control size. + + + + + + + + + + Specifies attributes that can be applied to dynamic controls that support GetContent. + + + + + + + Specifies a callback which returns the dynamic content for this control. + + + + + + + + + + Specifies attributes that can be applied to controls that support dynamic content. + + + + + + + Specifies whether to call callbacks to get dynamic content every time the control is dropped. + + + + + + + + + Attributes that specify a control's alignment. + + + + + + + + + + + + + + + + + + + + + + + Specifies attributes that specify how a control expands within its container + + + + + + + + + + + + + + + + + + Specifies the group style attributes + + + + + + + + + + + + + + + Specifies a callback which returns the style of a group. + + + + + + + + + Specifies the style of a Button + + + + + + + + + + + + + + + + ---------------------------------------------------------------------- + Global settings + ---------------------------------------------------------------------- + + + + + + + + Specifies attribute overrides for all controls with specified ID. + + Setting a property with Command element is equivalent to setting + same properties on all controls with same id in the ribbon, popup menus, status bar etc. + + For example + + <command idMso="Print" enabled="false"> + + disables all instances of Print button in the application UI. + + + + + + + + + + + ---------------------------------------------------------------------- + Controls + ---------------------------------------------------------------------- + + + + + + + + Base control type. + Doesn't define ID attributes. + Abstract type, not to be used directly. + + + + + + + + + + + Specifies a type of control that can be used to + enable, disable, or clone an existing control. + + + + + + + + + + + + + + + Specifies a clone of built-in control. + Control type is determined by source control. + Only the most common attributes can be applied here; to set + control-specific properties the actual control type must be specified. + + + + + + + + + Custom controls can't be cloned by id. + + + + + + + + + + + + Specifies a clone of built-in control that can be sized. + + + + + + + + + Custom controls can't be cloned by id. + + + + + + + The onAction property does not apply to 'control'. + + + + + + + + + + + + Specifies a clone of built-in or custom control in QAT. + + + + + + + + + Custom id to clone from. + Can refer to a custom ID in same file. + + + + + + + A qualified control ID. + + + + + + + + + + + + + + + Shows text and/or icon but can't have any associated actions. + + + + + + + + + "image" property is not applicable to labelControl. + + + + + + + "imageMso" property is not applicable to labelControl. + + + + + + + "getImage" callback is not applicable to labelControl. + + + + + + + "keytip" property is not applicable to labelControl. + + + + + + + "getKeytip" callback is not applicable to labelControl. + + + + + + + "showImage" property is not applicable to labelControl. + + + + + + + "getShowImage" callback is not applicable to labelControl. + + + + + + + + + + + + Specifies a fixed-size button. + Size of a button of this type is determined by its container such as a menu. + + + + + + + + + + + + + + + + + + Specifies a push-type button. + + + + + + + + + + + + + + + Specifies a button which is always visible. + + + + + + + + + "visible" property is not applicable to these types of buttons + because they are always visible. + + + + + + + "getVisible" property is not applicable to these types of buttons + because they are always visible. + + + + + + + + + + + + Specifies a fixed-size button type with an on/off state such as a Bold button. + + + + + + + + + + + + + + + Specifies a button type with an on/off state that can be sized. + + + + + + + + + + + + + + + Specifies a toggleButton which is always visible. + + + + + + + + + "visible" property is not applicable to these types of buttons + because they are always visible. + + + + + + + "getVisible" property is not applicable to these types of buttons + because they are always visible. + + + + + + + + + + + + + Specifies a check box. + + + + + + + + + "image" property is not applicable to checkBox. + + + + + + + "imageMso" property is not applicable to checkBox. + + + + + + + "getImage" callback is not applicable to checkBox. + + + + + + + "showImage" property is not applicable to checkBox. + + + + + + + "getShowImage" callback is not applicable to checkBox. + + + + + + + "showLabel" property is not applicable to checkBox. + + + + + + + "getShowLabel" callback is not applicable to checkBox. + + + + + + + + + + + + + Specifies an edit box control type. + + OnChange callback reports new text. + + + + + + + + + + + Specifies maximum number of characters the user may input. + + + + + + + Specifies a callback which returns text to be inserted in the edit box before begins editing. + + + + + + + Specifies a callback which responds on change of selection. + + + + + + + Specifies a representative string which should fit in the control. + E.g. if the control is meant for a credit card number a string of 16 digits + ensures appropriate control size. + + + + + + + + + + + + + Represents a selection in a comboBox or dropDown control type. + + + + + + + Specifies the ID of a gallery item. Gallery items cannot use idMso or idQ. + + + + + + + Specifies text label. + + + + + + + Specifies the image. + + + + + + + Specifies a built-in image. + + + + + + + Specifies the screentip. + + + + + + + Specifies the SuperTip. + + + + + + + + + + Specifies a comboBox control type. + + Contains options (multiple-choice item) + + OnChange behavior is same as in EditBox (the text). + Callback can't tell if the value is typed in or selected. + + + + + + + + + + One of the items to choose from. + When selected, the label property of the item becomes text content of + the edit box. + + + + + + + + + + + + + + + + Specifies a drop-down control type with a fixed-size. + Contains options followed by buttons. Order is important - buttons last. + OnAction reports the selected option. + + + + + + + + + + One of the items to choose from. + + + + + + + Button which invokes a different command. + Pushing a button doesn't have any effect on selection. + + + + + + + + + + + + Specifies a callback which returns the ID of currently selected item. + + + + + + + Specifies a callback which returns the index of currently selected item. + + + + + + + Specifies if the label is shown or hidden on dropdown items. + + + + + + + + + + + + Specifies a drop-down grid control that can be sized. + + + + + + + + + + + Specifies number of columns in dropdown gallery. + + + + + + + Specifies number of rows in dropdown gallery. + + + + + + + Specifies item width in pixels. + + + + + + + Specifies item height in pixels. + + + + + + + Specifies a callback which returns the item width. + + + + + + + Specifies a callback which returns the item height. + + + + + + + Specifies if the label is shown or hidden on gallery items. + + + + + + + Specifies whether the gallery should be shown in-ribbon. This attribute + is not supported in Ribbon Extensibility documents. + + + + + + + + + + + + Gallery - choose one option from a grid of options. + + + + + + + + + + + + + + Defines a group of controls allowed in all menus. + + + + + + + Control element can enable, disable or clone existing controls. + Creating a new (custom) control with Control element is not possible + because the control type is not specified. + + + + + + + Button control. + + + + + + + CheckBox control. + + + + + + + DropDownGrid-type gallery control. + + + + + + + toggleButton control. + + + + + + + Control group separator. + + + + + + + + + + + Defines menu or splitButton controls. + + + + + + + SplitButton control. + + + + + + + Menu. + + + + + + + Dynamic menu. + + + + + + + + + + + Defines menu or split button controls with title, for use in Office menu. + + + + + + + SplitButton control. + + + + + + + Menu. + + + + + + + DynamicMenu. + + + + + + + + + + + + + + + + + + + + + + + + + + + Specifies a menu with a fixed-size button. + Contains one or more controls or other Menus. + + + + + + + + + + + + + + + Specifies size of menu items. + + + + + + + + + + + + + + Specifies a dynamic menu with a fixed-size button. + + + + + + + + + + + + + + + + + + + Specifies a menu with a fixed-size button. + Contains one or more controls or other Menus. + Implements "Title" property. + + + + + + + + + + + + + + + + Specifies size of menu items. + + + + + + + + + + + + + Specifies a menu with a button that can be sized. + Contains one or more controls or other Menus. + + + + + + + + + + Specifies size of menu items. Large menu items show their description property. + + + + + + + + + + + + Specifies a dynamic menu with a button that can be sized. + Contains one or more controls or other Menus. + + + + + + + + + + + + + + + + Specifies a split button (button type or menu) with a fixed-size. + Split button contains one button (or toggle button) and one menu. + Abstract type. + + + + + + + + + + + + + + + Specifies the properties which are restricted from splitButtons + because they are inherited from the button inside of the splitButton. + + + + + + + + + This property is inherited from the button inside of the splitButton. + + + + + + + This property is inherited from the button inside of the splitButton. + + + + + + + This property is inherited from the button inside of the splitButton. + + + + + + + This property is inherited from the button inside of the splitButton. + + + + + + + This property is inherited from the button inside of the splitButton. + + + + + + + This property is inherited from the button inside of the splitButton. + + + + + + + This property is inherited from the button inside of the splitButton. + + + + + + + This property is inherited from the button inside of the splitButton. + + + + + + + This property is inherited from the button inside of the splitButton. + + + + + + + This property is inherited from the button inside of the splitButton. + + + + + + + This property is inherited from the button inside of the splitButton. + + + + + + + + + + + + Specifies a split button (button type or menu) with a fixed-size. + Split button contains one button (or toggle button) and one menu. + + + + + + + + + + + Button control. + + + + + + + Button with on/off state, such as Bold. + + + + + + + + Menu. + + + + + + + + + + + + + Specifies a split button (button type or menu) with a fixed-size. + Split button contains one button (or toggle button) and one menu. + + + + + + + + + + + Button control. + + + + + + + Button with on/off state, such as Bold. + + + + + + + + Menu. + + + + + + + + + + + + + Specifies a split button (button type or menu) that can be sized. + + + + + + + + + + + + + + + Defines a group of control types. + + + + + + + Control element can enable, disable or clone existing controls. + Creating a new (custom) control with Control element is not possible + because the control type is not specified. + + + + + + + LabelControl control. + Shows text and/or icon but can't have any associated actions. + + + + + + + Button control. + + + + + + + Button with on/off state, such as Bold. + + + + + + + CheckBox control. + + + + + + + EditBox control. + + + + + + + ComboBox control. + + + + + + + DropDown control. + + + + + + + Gallery control. + + + + + + + Menu. + + + + + + + Dynamic menu. + + + + + + + SplitButton control. + + + + + + + Box control. + + + + + + + ButtonGroup control. + + + + + + + + + + ---------------------------------------------------------------------- + Containers + ---------------------------------------------------------------------- + + + + + + + + Specifies a dialog launcher with options for the associated group. + + + + + + + + Dialog launcher - a widget that brings up a dialog with advanced options for this group. + + + + + + + + + + + + Specifies a Box control - a horizontal grouping container. + + + + + + + + + + + Specifies how controls are displayed within the box. + + + + + + + + + + + Specifies a control group separator - a vertical bar. + + + + + + + + + + + + + Specifies a menu separator - a horizontal bar that separates menu items. + + + + + + + + + + + + + + + + + + Specifies a ButtonGroup control - a horizontal container with an integrated look. + + + + + + + + + Control element can enable, disable or clone existing controls. + Creating a new (custom) control with Control element is not possible + because the control type is not specified. + + + + + + + Button control. + + + + + + + Button with on/off state, such as Bold. + + + + + + + Gallery control. + + + + + + + Menu. + + + + + + + Dynamic menu. + + + + + + + SplitButton control. + + + + + + + Control separator. + + + + + + + + + + + + + + + + Specifies a group that contains other control types. + + + + + + + + + + + Control group separator. + + + + + + + + + Dialog launcher - a widget that brings up a dialog with advanced options for this group. + + + + + + + + + + + + + + + Specifies whether the group should automatically scale its contents. + + + + + + + Specifies whether the group's contents should be vertically centered + + + + + + + + + + + Specifies a tab that contains groups with other controls. + + + + + + + + + + Group. Contains controls. + + + + + + + + + + + + + + + + + + + Specifies Quick Access Toolbar items (shared or document-specific). + + + + + + + + + Control element can enable, disable or clone existing controls. + Creating a new (custom) control with Control element is not possible + because the control type is not specified. + + + + + + + Button control. + + + + + + + Control group separator. + + + + + + + + + + + + + Specifies Quick Access Toolbar. + Contains two control collections: + Shared (applied to all windows and documents) and + Document (attached to a document). + + + + + + + + Custom set of controls shared between all windows or instances of the application. + + + + + + + Custom set of controls attached to the current document. + + + + + + + + + + + + Specifies a collection of tabs. + + + + + + + + Tab. + + + + + + + + + + + + Specifies a collection of contextual tab sets. + + + + + + + + A contextual Tab. + + + + + + + + Specifies ID of a built-in control. + + + + + + + + + + + + Specifies a collection of contextual tab sets. + + + + + + + + Tab Set. + + + + + + + + + + + Specifies a ContextMenu. + Contains one or more controls in sections divided by separators. + + + + + + + + + + + + + + ---------------------------------------------------------------------- + Root elements + ---------------------------------------------------------------------- + + + + + + + + Specifies a collection of Command elements. + + + + + + + + Specifies attribute overrides for all controls with specified idMso. + + + + + + + + + + + Specifies the Ribbon which contains the tabs, menu, Quick Access Toolbar control types. + + + + + + + + Quick Access Toolbar. + Contains two control collections: + Shared (applied to all windows and documents) and + Document (attached to a document). + + + + + + "id" attribute must be unique within QAT, although + it doesn't have to be uniquie across the file. + + + + + + + + + + A collection of tabs. + + + + + + + A collection of contextual tab sets. + + + + + + + + Specicies the mode where most of the standard UI is turned off and + replaced with custom UI specified here. + + + + + + + + + Specifies a collection of ContextMenus. + + + + + + + + + + + + Specifies the root element of the customization XML returned by dynamicMenus. + + + + + + + + + + + + + + Specifies size of menu items. + + + + + + + + + + Specifies the root element of the customization XML used in dynamicMenu's GetContent callback. + + + + + + + + + ---------------------------------------------------------------------- + Backstage elements + ---------------------------------------------------------------------- + + + + + + + Specifies a generic button in the Backstage + + + + + + + + + + + + + + + + A BackstageButtonBase which additionally has the screentip attributes + + + + + + + + + + + + + A BackstageRegularButton that additionally has the group layout attributes + + + + + + + + + + + + + + A BackstageButtonBase which additionally has the description attributes + + + + + + + + + + + + + A BackstageRegularButton that also has FastCommand-related attributes + + + + + + + + + + + + + + Specifies a generic CheckBox in the Backstage + + + + + + + + + + + + + + + A BackstageCheckBox which has the additional attributes for group controls + + + + + + + + + + + + + + + A BackstageCheckBox which exists in a primary menu + + + + + + + + + + + + + An toggle button which exists in a primary menu + + + + + + + + + + + + + Specifies an EditBox in the Backstage + + + + + + + + + + + + + + + + + + + Specifies a drop-down control + + + + + + + + + + + + + + + + + + + + + + + + + Specifies a group of radio buttons + + + + + + + + + + + + + + + + + + + + + + + Specifies a combo box control + + + + + + + + + + + + + + + + + + + + + + + + Represents a selection item in a Backstage DropDown, ComboBox or RadioGroup + + + + + + Specifies the ID of an item. Items cannot use idMso or idQ. + + + + + + + + + + Specifies a hyperlink control + + + + + + + + + + + + + + + + + + + + Specifies a label control + + + + + + + + + + + + + + + Specifies a primary button or menu + + + + + + + + + + + + Defines the controls that can go in a Backstage MenuGroup + + + + + + + + + + + + + + Backstage MenuGroup + + + + + + + + + + + + + Specifies size of menu items. + + + + + + + + + Specifies a Backstage menu + + + + + + + + + + + + + + + + + + + Specifies a BackstageMenu which also includes the screentip attributes + + + + + + + + + + + + + Specifies a BackstageMenu which also includes the + description/getDescription attributes + + + + + + + + + + + + + An image-hosting control + + + + + + + + + + + + + Specifies a collection of controls that can live in groups. + + + + + + + All of the controls which are allowed inside of groups. + + + + + + + + + + Specifies a group in the backstage. + + + + + + + + Primary item (button/menu). + + + + + + + + TopItems. + + + + + + + TopItems. + + + + + + + + + + + + + + + + + Specifies a collection of headerButton controls. + + + + + + + button + + + + + + + + + + + + Specifies a TaskGroup. + + + + + + + TaskGroup category + + + + + + + + + + + + + + + + + Specifies a collection of TaskGroupTask controls. + + + + + + + task + + + + + + + + + + + + + + Specifies a task in a TaskGroup + + + + + + + + + + + + + + + + + + Specifies a TaskFormGroup. + + + + + + + TaskFormGroup category + + + + + + + + + + + + + + + + Specifies a collection of TaskFormGroupTask controls. + + + + + + + task + + + + + + + + + + + + + + Specifies a task in a TaskFormGroup + + + + + + + Group. + + + + + + + + + + + + + + + + + + Specifies a groupBox. + + + + + + + + + + + + + + Specifies a layoutContainer. + + + + + + + + + + + Specifies side of the layoutContainer where the children controls will be aligned. + + + + + + + + + + + + + + + + + + + Specifies the directions in which the layoutContainer will expand to fill its parent container. + + + + + + + + + + + + + + + Specifies the layout direction for the children controls. + + + + + + + + + + + + + + + Defines the controls that can go in a group. + + + + + + + + + + + + + + + + + + + + + Specifies the list of simple group types. + + + + + + + A regular group. + + + + + + + A TaskGroup. + + + + + + + + + + Specifies a collection of groups, which is either one taskFormGroup or + a set of simple groups. + + + + + + + + A TaskFormGroup. + + + + + + + + + + + + + + Specifies a collection of simple groups. + + + + + + + + + + + Specifies a tab that contains a fastCommands section and group controls. + + + + + + + The left column of groups. + + + + + + + The right column of groups. + + + + + + + + + + + + + + + Specifies the division of the tab's columns, as a percentage of the width of the entire tab. + + + + + + + + + + + + + Specifies the minimum width of the tab's first column in pixels. + + + + + + + + + + + + + Specifies the maximum width of the tab's first column in pixels. + + + + + + + + + + + + + Specifies the minimum width of the tab's second column in pixels. + + + + + + + + + + + + + Specifies the maximum width of the tab's second column in pixels. + + + + + + + + + + + + + + + + Specifies the Backstage tag + + + + + + + + + A tab. + + + + + + + FastCommand-style button + + + + + + + + + Specifies a callback which is invoked when a Backstage is opened. + + + + + + + Specifies a callback which is invoked when a Backstage is closed. + + + + + + + + + + Specifies the root element of the customization file which is used to create or modify the Ribbon. + + + + + + + + Command overrides. + + + + + + + Ribbon. + + + + + + + Backstage. + + + + + + + ContextMenus. + + + + + + + + Specifies a callback which is invoked when custom UI is loaded. + IRibbonUI object is passed as a parameter. + + + + + + + Specifies a callback which is invoked to load custom images. + + + + + + + + + + Specifies the root element of the customization file which is used to create or modify the Ribbon. + + + + + + + diff --git a/sample/SampleAddIn/Properties/AssemblyInfo.cs b/sample/SampleAddIn/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c2933ee --- /dev/null +++ b/sample/SampleAddIn/Properties/AssemblyInfo.cs @@ -0,0 +1,42 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SampleAddIn")] +[assembly: AssemblyDescription("")] + +#if DEBUG +[assembly: AssemblyConfiguration("Debug")] +#else +[assembly: AssemblyConfiguration("Release")] +#endif + +[assembly: AssemblyCompany("caioproiete.net")] +[assembly: AssemblyProduct("SampleAddIn")] +[assembly: AssemblyCopyright("Copyright © 2018 Caio Proiete & Contributors")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("773f7798-9cf7-4cfa-8353-5d882d11490b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyInformationalVersion("1.0.0")] diff --git a/sample/SampleAddIn/Properties/ExcelDna.Build.props b/sample/SampleAddIn/Properties/ExcelDna.Build.props new file mode 100644 index 0000000..ae23b51 --- /dev/null +++ b/sample/SampleAddIn/Properties/ExcelDna.Build.props @@ -0,0 +1,48 @@ + + + + + + + + true + true + + + 32 + 64 + + + + + + false + + + -packed + + + diff --git a/sample/SampleAddIn/Ribbon.cs b/sample/SampleAddIn/Ribbon.cs new file mode 100644 index 0000000..e9827f9 --- /dev/null +++ b/sample/SampleAddIn/Ribbon.cs @@ -0,0 +1,259 @@ +// Copyright 2018 Caio Proiete & Contributors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; +using System.IO; +using System.Runtime.InteropServices; +using ExcelDna.Integration; +using ExcelDna.Integration.CustomUI; +using ExcelDna.Logging; +using Serilog; +using static SampleAddIn.AddIn; + +namespace SampleAddIn +{ + [ComVisible(true)] + public class Ribbon : ExcelRibbon + { + private ILogger _log = Log.Logger; + private IRibbonUI _ribbonUi; + + public override string GetCustomUI(string ribbonId) + { + try + { + _log = Log.ForContext(); + _log.Debug("Loading ribbon {ribbonId} via GetCustomUI", ribbonId); + + var xllFolderPath = Path.GetDirectoryName(ExcelDnaUtil.XllPath) ?? string.Empty; + var ribbonXmlFilePath = Path.Combine(xllFolderPath, $"{nameof(Ribbon)}.xml"); + + if (!File.Exists(ribbonXmlFilePath)) + { + throw new FileNotFoundException($"File not found: {ribbonXmlFilePath}", ribbonXmlFilePath); + } + + var ribbonXml = File.ReadAllText(ribbonXmlFilePath); + + _log.Debug("Ribbon XML {ribbonXml}", ribbonXml); + + return ribbonXml; + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + return null; + } + } + + public void OnLoad(IRibbonUI ribbonUi) + { + try + { + _log.Information("Loading Ribbon..."); + _ribbonUi = ribbonUi; + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + } + + public string SampleTab_GetLabel(IRibbonControl control) + { + try + { + var ribbonLabel = "Serilog -> LogDisplay"; + + // Excel 2013 + if (Math.Abs(ExcelDnaUtil.ExcelVersion - 15.0) < double.Epsilon) + { + ribbonLabel = ribbonLabel.ToUpperInvariant(); + } + + return ribbonLabel; + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + return control.Id; + } + } + + public void VerboseButton_OnAction(IRibbonControl control) + { + try + { + _log.Verbose("This is a **Verbose** message"); + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + } + + public void DebugButton_OnAction(IRibbonControl control) + { + try + { + _log.Debug("This is a **Debug** message"); + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + } + + public void InformationButton_OnAction(IRibbonControl control) + { + try + { + _log.Information("This is an **Information** message"); + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + } + + public void WarningButton_OnAction(IRibbonControl control) + { + try + { + _log.Warning("This is a **Warning** message"); + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + } + + public void ErrorButton_OnAction(IRibbonControl control) + { + try + { + _log.Error("This is an **Error** message"); + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + } + + public void ViewLogDisplayButton_OnAction(IRibbonControl control) + { + try + { + LogDisplay.Show(); + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + } + + public void ClearLogDisplayButton_OnAction(IRibbonControl control) + { + try + { + LogDisplay.Clear(); + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + } + + public string DisplayOrderMenu_GetImage(IRibbonControl control) + { + try + { + switch (LogDisplay.DisplayOrder) + { + case DisplayOrder.NewestLast: + return "EndOfDocument"; + + case DisplayOrder.NewestFirst: + return "StartOfDocument"; + + default: + throw new NotImplementedException(LogDisplay.DisplayOrder.ToString()); + } + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + return null; + } + } + + public bool LogNewestLastButton_GetPressed(IRibbonControl control) + { + try + { + return LogDisplay.DisplayOrder == DisplayOrder.NewestLast; + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + + return false; + } + + public void LogNewestLastButton_OnAction(IRibbonControl control, bool pressed) + { + try + { + LogDisplay.DisplayOrder = DisplayOrder.NewestLast; + _ribbonUi.InvalidateControl("DisplayOrderMenu"); + _ribbonUi.InvalidateControl("LogNewestLastButton"); + _ribbonUi.InvalidateControl("LogNewestFirstButton"); + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + } + + public bool LogNewestFirstButton_GetPressed(IRibbonControl control) + { + try + { + return LogDisplay.DisplayOrder == DisplayOrder.NewestFirst; + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + + return false; + } + + public void LogNewestFirstButton_OnAction(IRibbonControl control, bool pressed) + { + try + { + LogDisplay.DisplayOrder = DisplayOrder.NewestFirst; + _ribbonUi.InvalidateControl("DisplayOrderMenu"); + _ribbonUi.InvalidateControl("LogNewestFirstButton"); + _ribbonUi.InvalidateControl("LogNewestLastButton"); + } + catch (Exception ex) + { + ProcessUnhandledException(ex); + } + } + } +} diff --git a/sample/SampleAddIn/Ribbon.xml b/sample/SampleAddIn/Ribbon.xml new file mode 100644 index 0000000..8a697f9 --- /dev/null +++ b/sample/SampleAddIn/Ribbon.xml @@ -0,0 +1,35 @@ + + + + + + +