Skip to content

Commit

Permalink
Add Add-in Commands to the Ribbon to interop between JavaScript and C…
Browse files Browse the repository at this point in the history
…# with Blazor Pages. (#762)

* Initial Branch Custom Add-in Functions from Ribbon

* Made a little bit of progression on implementing Commands, not working though
To be continued

* Enabled JavaScript Add-in Commands (Color and Write), Blazor Functions still unable to be called from Add-in Commands. We know how to load the environment but Blazor load timing still arrives AFTER the function call.

* Got the Ribbon .NET Blazor Interop to work from the Ribbon to run C# Methods in the OfficeJS Ribbon context.

* Got everything to work, calling C# functions from the Ribbon, and calling JS functions from that C# function.

* Added JS - CS Interop Functions to Word Office Add-in, similar to what we did earlier with Excel.
Also some minor restructuring and fixes, removing obsolete code.

* Updated final Excel Checks, Readme still open to finalize.

* Making Minor Changes, still need to finalize Readme and checks before PR

* Updated ReadMe and cleaning up before creating PR to Microsoft Repo

* Remove generated items from csproj.user (in general I think .user should not even be in the project ...)

* Added some comments

* Update Samples/blazor-add-in/excel-blazor-add-in/excel-blazor-add-in/Pages/BubbleChart.razor.js

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/excel-blazor-add-in/excel-blazor-add-in/wwwroot/Commands/commands.js

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/excel-blazor-add-in/README.md

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/word-blazor-add-in/README.md

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/excel-blazor-add-in/excel-blazor-add-in/wwwroot/Commands/commands.js

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/excel-blazor-add-in/excel-blazor-sideloader/excel-blazor-sideloaderManifest/excel-blazor-sideloader.xml

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/excel-blazor-add-in/excel-blazor-sideloader/excel-blazor-sideloaderManifest/excel-blazor-sideloader.xml

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/excel-blazor-add-in/README.md

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/excel-blazor-add-in/README.md

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/excel-blazor-add-in/README.md

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/word-blazor-add-in/README.md

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/excel-blazor-add-in/README.md

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/word-blazor-add-in/README.md

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/word-blazor-add-in/README.md

Co-authored-by: David Chesnut <[email protected]>

* Update Samples/blazor-add-in/word-blazor-add-in/README.md

Co-authored-by: David Chesnut <[email protected]>

* Added suggestions from PR

* Added some errorhandling and fixing Excel API call

* Another missed change ...

---------

Co-authored-by: Maarten van Stam <[email protected]>
Co-authored-by: David Chesnut <[email protected]>
  • Loading branch information
3 people authored Apr 25, 2024
1 parent 05f76e7 commit 15b0646
Show file tree
Hide file tree
Showing 20 changed files with 730 additions and 212 deletions.
12 changes: 9 additions & 3 deletions Samples/blazor-add-in/excel-blazor-add-in/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ This sample shows how to build an Excel add-in using .NET Blazor technologies. B
- Initialize the Office JavaScript API library in Blazor context.
- Interact with Excel to manipulate worksheets.
- Interact with workbook content through Office JavaScript APIs.
- Interact with methods defined on the Blazor Pages.
- Interop between OfficeJS - JavaScript - C# and back to JavaScript.

## Applies to

Expand All @@ -38,9 +40,9 @@ This sample shows how to build an Excel add-in using .NET Blazor technologies. B
1. Download or clone the [Office Add-ins samples repository](https://github.com/OfficeDev/Office-Add-in-samples).
1. Open Visual Studio 2022 and open the **Office-Add-in-samples\Samples\blazor-add-in\excel-blazor-add-in\excel-blazor-add-in.sln** solution. (Do **not** open Visual Studio "as administrator". There is a bug that will prevent the add-in from sideloading when Visual Studio is elevated in this way.)
1. Choose **Debug** > **Start Debugging**. Or press F5 to start the solution.
1. When Excel opens, choose **Home** > **Show Taskpane**.

Next, try out the controls.
1. When Excel opens, choose **Sample Add-in** > **Show task pane** (if not already open).
1. Try out the controls on the task panes.
1. Try out the custom buttons on the **Sample Add-in** tab on the ribbon.

## Understand an Office Add-in in Blazor Context

Expand Down Expand Up @@ -94,6 +96,9 @@ The fundamental pattern includes the following steps.
1. Use **JSModule.InvokeVoidAsync** to call JavaScript functions from your C# code.
1. Call Office JS APIs to interact with the worksheet from JavaScript code.

### Blazor interop with Add-in Commands
This sample shows how to use Blazor with custom buttons on the ribbon. The buttons call the same functions that are defined on the task pane. This sample is configured to use the shared runtime which is required for this interop to work correctly.

## Debugging

This sample is configured to support debugging both JavaScript and C# files. New Blazor projects need the following file updates to support C# debugging.
Expand Down Expand Up @@ -131,6 +136,7 @@ Version | Date | Comments
---------| ---------------- | ------------------
1.0 | May 27, 2022 | Initial release
2.0 | February 1, 2024 | Upgraded to .NET 8
3.0 | April 18, 2024 | Added Add-in Commands, demo JS and C# Interop from the Ribbon

## Copyright

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<TargetOfficeVersion>15.0</TargetOfficeVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.1" PrivateAssets="all" />
<PackageReference Include="Microsoft.JSInterop.WebAssembly" Version="8.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="8.0.3" PrivateAssets="all" />
<PackageReference Include="Microsoft.JSInterop.WebAssembly" Version="8.0.3" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
/* Copyright(c) Maarten van Stam. All rights reserved. Licensed under the MIT License. */

using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices.JavaScript;
using System.Runtime.Versioning;

namespace BlazorAddIn.Pages
{
/// <summary>
/// Starter class to demo how to create a bubble chart.
/// </summary>
[SupportedOSPlatform("browser")]
public partial class BubbleChart
{
[Inject]
public IJSRuntime JSRuntime { get; set; } = default!;
public IJSObjectReference JSModule { get; set; } = default!;
[Inject, AllowNull]
private IJSRuntime JSRuntime { get; set; }
private IJSObjectReference? JSModule { get; set; }

protected override async Task OnAfterRenderAsync(bool firstRender)
{
Expand All @@ -31,8 +35,28 @@ private async Task CreateTable() =>
/// <summary>
/// Function to create the actual bubble chart.
/// </summary>
private async Task CreateBubbleChart() =>
private async Task CreateBubbleChart() =>
await JSModule.InvokeVoidAsync("createBubbleChart");

[JSImport("createTable", "BubbleChart")]
internal static partial Task CreateImportedTable();

[JSImport("createBubbleChart", "BubbleChart")]
internal static partial Task RunCreateChart();

[JSInvokable]
public static async Task CreateBubbles()
{
await JSHost.ImportAsync("BubbleChart", "../Pages/BubbleChart.razor.js");
await CreateImportedTable();
await RunCreateChart();
}

[JSInvokable]
public static string SayHelloBubble(string name)
{
return $"Hello Bubble, {name} from BubbleChart!";
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,33 @@
* This bubble chart sample is extracted from the excellent helper tool called Script Lab.
* Find this sample and more at https://aka.ms/getscriptlab.
*/
console.log("Loading BubbleChart.razor.js");

export async function createTable() {
await Excel.run(async (context) => {
context.workbook.worksheets.getItemOrNullObject("Sample").delete();
const sheet = context.workbook.worksheets.add("Sample");

const inventoryTable = sheet.tables.add("A1:D1", true);
inventoryTable.name = "Sales";
inventoryTable.getHeaderRowRange().values = [["Product", "Inventory", "Price", "Current Market Share"]];

inventoryTable.rows.add(null, [
["Calamansi", 2000, "$2.45", "10%"],
["Cara cara orange", 10000, "$2.12", "45%"],
["Limequat", 4000, "$0.70", "66%"],
["Meyer lemon", 100, "$2.65", "5%"],
["Pomelo", 4000, "$1.69", "14%"],
["Yuzu", 7500, "$3.23", "34%"]
]);

sheet.getUsedRange().format.autofitColumns();
sheet.getUsedRange().format.autofitRows();

sheet.activate();
await context.sync();
});
}

export async function createBubbleChart() {
await Excel.run(async (context) => {
Expand Down Expand Up @@ -51,28 +78,3 @@ export async function createBubbleChart() {
});
}

export async function createTable() {
await Excel.run(async (context) => {
context.workbook.worksheets.getItemOrNullObject("Sample").delete();
const sheet = context.workbook.worksheets.add("Sample");

let inventoryTable = sheet.tables.add("A1:D1", true);
inventoryTable.name = "Sales";
inventoryTable.getHeaderRowRange().values = [["Product", "Inventory", "Price", "Current Market Share"]];

inventoryTable.rows.add(null, [
["Calamansi", 2000, "$2.45", "10%"],
["Cara cara orange", 10000, "$2.12", "45%"],
["Limequat", 4000, "$0.70", "66%"],
["Meyer lemon", 100, "$2.65", "5%"],
["Pomelo", 4000, "$1.69", "14%"],
["Yuzu", 7500, "$3.23", "34%"]
]);

sheet.getUsedRange().format.autofitColumns();
sheet.getUsedRange().format.autofitRows();

sheet.activate();
await context.sync();
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,26 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

namespace BlazorAddIn.Pages
{
/// <summary>
/// Starter class to demo how to insert `Hello world!` text.
/// </summary>
public partial class Index
{
[Inject]
public IJSRuntime JSRuntime { get; set; } = default!;
public IJSObjectReference JSModule { get; set; } = default!;
[Inject, AllowNull]
private IJSRuntime JSRuntime { get; set; }
private IJSObjectReference JSModule { get; set; } = default!;

protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
Debug.WriteLine("Hit OnAfterRenderAsync in Index.razor.cs!");
Console.WriteLine("Hit OnAfterRenderAsync in Index.razor.cs in Console!");
JSModule = await JSRuntime.InvokeAsync<IJSObjectReference>("import", "./Pages/Index.razor.js");
}
}
Expand All @@ -27,5 +32,11 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
/// </summary>
private async Task HelloButton() =>
await JSModule.InvokeVoidAsync("helloButton");

[JSInvokable]
public static string SayHelloIndex(string name)
{
return $"Hello Index, {name} from Index!";
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
/**
* Basic function to show how to insert a value into cell A1 on the selected Excel worksheet.
*/
console.log("Loading Index.razor.js");

export function helloButton() {

console.log("We are now entering function: helloButton");

return Excel.run(context => {


// Insert text 'Hello world!' into cell A1.
context.workbook.worksheets.getActiveWorksheet().getRange("A1").values = [['Hello world!']];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
* - Configuring Blazor settings.
*/

console.log("Loading BlazorAddin.lib.module.js");

/**
* beforeStart(options, extensions):
*
Expand All @@ -19,14 +21,17 @@ export async function beforeStart(wasmoptions, extensions) {
console.log("We are now entering function: beforeStart");

Office.onReady((info) => {

// Office Finished Loading
console.log("Office onReady.");

// Check that we loaded into Excel.
if (info.host === Office.HostType.Excel) {
console.log("We are now hosting in Excel.");
}
else {
console.log("We are now hosting in The Browser (of your choice).");
}
console.log("Office onReady.");
});
}

Expand All @@ -38,4 +43,5 @@ export async function beforeStart(wasmoptions, extensions) {
*/
export async function afterStarted(blazor) {
console.log("We are now entering function: afterStarted");
}
}

Loading

0 comments on commit 15b0646

Please sign in to comment.