public class Blazor in WordPress – Multiple Components

{

In my previous post, I showed how to simply embed a single Blazor Component inside a WordPress page or post. However, what I really want is the chance to willy-nilly throw in as many components as I want, wherever I want. This runs into some problems. If you try to just copy/paste my code from the first post multiple times, and run it with your dev tools open, you’ll see multiple errors.

 

The first issue is with the line <script src="_framework/blazor.webassembly.js"></script>. As with any javascript file, you should only import blazor.webassembly one time, not multiple times. Sure, I could remember just to do that the first time, but it would be even nicer to have it built into my WordPress blog, and never have to worry about adding that line. It’s also more “correct” for websites to import scripts and other files in the head or at the bottom of the body (footer area), rather than in the midst of the content.

 

If this were a custom website, I would just add the tag to index.html. But with WordPress, there’s lots of warnings about interfering scripts, loading order, and so forth, so they don’t recommend you do this yourself. Instead, I installed a plugin, Header and Footer Scripts, which gives you WP UI-level control over custom tags in a header and/or footer.

 

After installing the plugins, I moved the blazor.webassembly script to the header, and reloaded to make sure everthing still worked. I discovered that I also had to move <base href="/" /> to make it still work. But again, this is something you would only want to do once per page. (And, side note, it’s the biggest failing of this whole setup, as redirecting all url calls can interfere with other WP plugins.)

 

Finally, if we’re going to move scripts, we should also move any stylesheet link tags. With all those moved out of the way, now the in-post html looks much more concise and neat:

 

<div id="app">Loading...</div>

 

Great! But now…I want two different components. OK, so, obviously, I should replace the id="app" with some other ids. Let’s look again at what the reference looks like in our Blazor Web Assembly Program.cs file:

 

public static async Task Main(string[] args)
{
var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("#app");

builder.Services.AddScoped(
sp => new HttpClient {BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)});

await builder.Build().RunAsync();
}

[Program.Main]

 

We already mentioned in the last post that you can replace <App> and "#app" with your own razor component file and id tag. So I tried adding two.

 

builder.RootComponents.Add<DataGrid>("#grid");
builder.RootComponents.Add<MusicKeyboard>("#keyboard");

 

And this definitely worked with two Id’ed div elements in a page! Unfortunately…if you happen to only want to use one of your two components, then Blazor throws an error that it can’t find the matching div for the other one!

 

My first attempt to fix this was to revert back to just loading the App razor component, and using logic inside that to decide which other component to show. This turned out to work for single components, but Blazor would get confused if it saw two "app" divs!

 

Luckily, after some more Google-fu, I stumbled on this GitHub issue: Unable to use RootComponents twice on same page, where the original poster, Ecroyd, came up with a clever workaround of using a custom element tag (type) for each component, looking up which components are on the page with JSInterop, and then only adding the RootComponents that are found!

 

You can see Ecroyd’s version on the link above, but I did some more tweaking. I decided I would rather keep these div elements, and instead add a class="blazor-component" to identify each.

 

var jsRuntime = builder.Services.BuildServiceProvider().GetRequiredService<IJSRuntime>();
var module = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "/componentFinder.js");
var json = await module.InvokeAsync<JsonElement>("getBlazorComponents");
foreach(var id in json.EnumerateArray())
{
switch (id.ToString())
{
case "blazor-data-grid":
builder.RootComponents.Add<BdGridDemo>("#blazor-data-grid");
break;
case "blazor-music-keyboard":
builder.RootComponents.Add<MusicKeyboardDemo>("#blazor-music-keyboard");
break;
}
}

[Program.Main changed code]

 

export function getBlazorComponents() {
return Array.from(document.querySelectorAll('.blazor-component')).map(a => a.id);
}

[componentFinder.js lookup module]

 

Now, for each component I want to embed, I add the following (some styling added for layout):

 

<div class="blazor-component" style="height: 550px; background: white; padding: 10px; overflow-x: scroll;" id="blazor-music-keyboard">Loading Blazor Music Keyboard ... </div>

(EDIT: Apologies for weird formatting, I’ve made some updates to the components and have lost formatting along the way, haven’t had a chance to fix it. Apparently css can be a real gotcha for this hybrid approach.)

 

Loading Blazor Music Keyboard …

 

Or

 

<div class="blazor-component" style="height: 800px; overflow-y: scroll; width: 100%; background: white; color: black; padding: 20px; font-family: arial;" id="blazor-data-grid">Loading Blazor Data Grid ... </div>

 

 

Loading Blazor Data Grid …
}

public class Embedding Blazor Components in WordPress

{

In my previous post, Blazor Data Grid, I showed off a new Blazor web component, and at the bottom of the post, I actually had a demo version of the component right here in this blog, which is running on WordPress. Hat tip to Virtual Dan at http://dano.vfsystems.net/2020/03/blazor-and-wordpress/ for getting me pointed in the right direction!

 

The gist of it is, since Blazor components can run in WebAssembly, all you need for a functioning embedded component is a Blazor WebAssembly project with a single component, published up to a folder in your WordPress (or other site) directory, a script tag to load blazor’s runtime, and a div with a pre-determined Id.

 

I started with the default Blazor Web Assembly template in Rider (my IDE of choice, but VS or VS Code work fine as well). In Program.Main, you see the following line:

 

builder.RootComponents.Add<App>("#app");

 

This defines the key div as having id="app", and points to a blazor component or razor file named App.razor. You can of course change both the Id string value and the razor file loaded. In my case, I decided that I didn’t need all the routing logic in App.razor for an embedded component project, so I deleted this (and many other files). At first, I just pointed to the component I wanted to render. Note that if you change the Id, you will also want to update your index.html file to match, so you can test your application. Running in debug, you get a simple rendering of your component in a blank page.

 

Loading Blazor Music Keyboard …

[Demo Musical Keyboard (Xylophone) Component]

 

Now that we have a working Blazor Wasm component, we want to get it up to our WordPress server. I recommend setting up some form of automated deployment on git commit, so that you don’t have to manually copy files every time you make a change (I use Azure DevOps Pipelines, but there are many solutions). Basically, you want everything in the /wwwroot folder of your publishing step to be directly copied into your root WordPress folder, like say /etc/wordpress/. This should be the same folder as wp-config.php.

 

That “everything” mentioned above includes two important folders, _content and _framework. _framework is the .NET Runtime and Wasm assemblies. We will discuss _content later. You should also see your index.html (although we won’t be using this), and any css or javascript files you created in your wwwroot.

 

Once the files are in place, load up the WordPress post or page editor, and add a “Custom HTML” block. Add the following code (I’m reverting back to the default “app” id here):

 

<div>
  <base href="/" />
<link href="YourApplication.styles.css" rel="stylesheet" />
  <div id="app">Loading...</div>
<script src="_framework/blazor.webassembly.js"></script>
</div>

 

This is based on Virtual Dan’s version, (thanks again). Let’s break it down.

 

The stylesheet link is only important if you actually created any styles for your component. We’ve already mentioned that we need a div with the correct Id. Whatever you put inside the div (e.g., “Loading…”) will show for a second or two while blazor boots up. Then it gets overwritten by the contents of your component. Below this is the script that loads Blazor Web Assembly.

 

I noticed the <base href="/" /> in Virtual Dan’s source code on his site. He doesn’t mention it in the explanations, but I figured out the reason for this. Without re-setting the base url, I would get errors with looking for blazor.webassembly.js at whatever the page url is, like https://tocode.software/2021/03/04/Blazor/_framework/blazor.webassembly.js. Obviously, I don’t want to put my framework at this location on disk, if I want to share it with multiple pages in the future, and prevent it from breaking if the url ever changes. I did tinker around with starting the script src with and without the forward slash, but it didn’t seem to work either way, until I discovered what Dan was doing with the base href.

 

If you’ve successfully followed thus far, publish or preview your wordpress page, and give yourself a high five for running Blazor in WordPress! I will follow up in the next few days with another post about refactoring and supporting multiple components.

}

public class Blazor Data Grid

{

In my day job, I am required to create and maintain applications with many data grids, such as search results. Since this company sells windows applications, the WPF DataGrid is our go-to tool to display these results in a rich, interactive context.

 

In my spare time, I enjoy continuing my work with Asp.NET Core web applications, and now Blazor as the new component-based framework for C# web development. However, Blazor is still relatively new, and I didn’t find an example of a DataGrid like in WPF, except from professional component-making companies like SyncFusion and Telerik. (NOTE: Since starting this, I have found Blazorise, and I’ll have to explore their data grid to see if I want to use/contribute to that rather than my own).

 

So I decided it would be a fun side project to design my own data grid in Blazor.

 

I’m still learning the best way to build and share on GitHub, but I fired up a new repository, TimPurdum/blazor-apps (github.com), and created a solution with two projects: a demo Blazor server-side application, and a razor component library to hold all the actual controls (so I can later package this into a nuget package).

 

After having a project structure, I needed to decide on the component structure. DataGrids are tricky because they aren’t simply a single hierarchy. Rows in a data grid are representations of items in a list. Each cell in the row maps to a property on the item. So far, so good. However, Columns in data grids can have their own values, such as size, data type, formatting, etc. So when you are generating a cell in a data grid, you really have to pay attention to both the column and the row. You also need to create a way to let the developer specify column attributes. And then, if they don’t specify, you should auto-generate columns from the item properties. For example, a property of type bool should map to an <input type="checkbox">.

 

In my DataGrid library, I created a base BdGridComponent, inheriting Blazor’s ComponentBase, from which all my other components could inherit. This class included exposed Parameter properties for many styling values, such as Font, Alignment and Color, so that these could be mapped from code rather than added as css by the consumer. It also defined IsEditable, and a base BuildStyle() method that would then convert the style parameters into css.

BdGridComponent
Lots of styling parameters

 

With this base created, I next tackled the BdColumnDefinition, which is again mostly about styling, but also requires tracking a few extra fields. BindingField will be the property name to bind to this column, and FieldType is a separate type enum to determine how to display the input elements in that column.

BdColumnDefinition.cs

 

I did decide to make each Cell in the grid an input, even when editing is disabled. This just makes it easier to code, rather than having to change the element type when going from editable to non-editable. BdInputCell is my base class, and then I have a variety of child types that inherit this.

 

BdInputCell.cs

 

Speaking of the cells, I am using a mix of C# and Razor files, with the “Code-Behind” pattern, so there is a BdInputCell.razor file, and a BdInputCell.razor.cs code behind file. The IDE does a nice job organizing these, and I much prefer this pattern to the @code {} block in the razor file, especially when the C# starts getting long and complex. If no layout was needed, such as the base BdInputCell, I could stick with a C# class. If no code was needed (or a very small amount), just a razor file would do. This also works well with the Blazor CSS Isolation pattern of using BdInputCell.razor.css for component styling.

 

Using generics, and allowing for multiple mixed patterns of C# Type vs. my FieldType and input types, the Input Cells had to keep track of both an object? Value and a T TypedValue to support proper data binding. This is a pretty simple swap, since the values are actually identical, but it allows the blazor @bind to work correctly.

 

Rolling back up from the input cells, I had to create a BdGridRow. This is where a single Item in the source list is read based on the ColumnDefinitions, and each Cell is created. It’s basically a big switch statement, which also handles event bubbling between the cells and the parent grid.

 

BdGridRow.razor

 

The BdGrid object defines the whole grid as a scrollable div, a header row, and the grid rows. If no column definitions are provided by the consumer, it must iterate through the generic item type and use reflection to create logical columns to display the data. It also needs to handle all data changes, and keeping the bound ItemsSource in sync.

 

BdGrid.razor

 

Under the hood, BdGrid is using the Blazor Virtualize component, which allows the grid to only load the rows necessary for viewing, rather than a potentially huge set of rows in a large collection. This works well, however, I discovered that it does not respond well to binding values changing on it’s Items property. I’m sure there is a more elegant solution to the issue, but after struggling for awhile, I finally settled on a pattern of giving it an empty items list, waiting for a refresh, then giving it the updated list.

 

While developing the grid, I also created a simple blazor test page to tweak all the settings and verify the binding. I plan to keep adding features here as well as to the grid itself. You can see the whole application below or at https://demo.tocode.software/datagrid. I will write another post shortly about how I managed to embed a blazor component into a wordpress blog. Please feel free to check out the code, use it, and make a pull request or report a bug if you have feedback!

 

Loading Blazor Data Grid …

 

 

}

public class Episode 13: Collections & Generics

{

Subscribe

public void Summary()

{

Tim & Tim discuss collections, all the way from IL arrays to .NET Lists, Dictionaries, HashSets, and generics!

}

public void Links()

{

}

public void HotSpot()

{

}

}

public class Episode 12: Xamarin and Mobile Development

{

Tim Jay interviews Tim Purdum about developing for iOS and Android using Xamarin and Xamarin.Forms.

Subscribe

public void Summary()

{

Tim Jay interviews Tim Purdum about developing for iOS and Android using Xamarin and Xamarin.Forms.

}

public void Links()

{

}

public void HotSpot()

{

}

}

public class Episode 11: MVVM Part Deux

{

Tim and Tim revisit the MVVM pattern and dive deeper into issues and details, like whether a control should have it’s own viewmodel, and which came first, the VM or the V?

Subscribe

public void Summary()

{

Tim and Tim revisit the MVVM pattern and dive deeper into issues and details, like whether a control should have it’s own viewmodel, and which came first, the VM or the V?

}

public void Links()

{

}

public void HotSpot()

{

  • Zeplin.io – Convert Adobe design files directly into UI components in Xamarin Forms!

}

}

public class Episode 10: NPoco and Other ORMs

{

Tim P. interviews Tim J. about ORMs, and specifically a little-known yet powerful .NET ORM called NPoco.

Subscribe

public void Summary()

{

Tim P. interviews Tim J. about ORMs, and specifically a little-known yet powerful .NET ORM called NPoco.

}

public void Links()

{

}

public void HotSpot()

{

  • JSON to POCO Conversion
    • easily convert a json file to a C# class
  • GitHub
    • read through other coder’s source to learn new tips and tricks
    • clone repos locally to use your IDE to browse code

}

}

public class Episode 9: Biting into Blazor

{

Tim J. interviews Tim P. about the new .NET Core Blazor web UI framework, it’s history, and where it is headed.

Subscribe

public void Summary()

{

Tim J. interviews Tim P. about the new .NET Core Blazor web UI framework, it’s history, and where it is headed.

}

public void Notes()

{

I (Tim P.) was a little out of date with my information on this episode, as Blazor Web Assembly was officially released by Microsoft last month!

}

public void Links()

{

 }

 

public void HotSpot()

{

  • CPU-Z – Free utility that provides detailed analysis of your hardware,
  • Azure –  Microsoft Cloud Service Provider

}

}

public class Episode 8: To Your Battle Stations!

{

Tim & Tim discuss their current workstation hardware and accessory setups, as well as some history on past pcs and purchases.

Subscribe

public void Summary()

{

Tim & Tim discuss the challenges and rewards of becoming team members vs. working as a solo dev.

}

public void Links()

{

Tim P’s Battle Station

Tim J’s Battle Station

}

public void HotSpot()

{

}

}

public class Using MVVM ViewModels Cross-Platform

{

In episode 7 of the ToCode.Software podcast, we discussed the MVVM framework. In that episode, I (Tim Purdum) asserted that, if designed carefully, you could reuse a ViewModel across multiple UI frameworks.

To demonstrate this point, I made a simple demo application at https://github.com/TimPurdum/Mvvm.

public void ProvingAPoint()

{

In episode 7 of the ToCode.Software podcast, we discussed the MVVM framework. In that episode, I (Tim Purdum) asserted that, if designed carefully, you could reuse a ViewModel across multiple UI frameworks.

To demonstrate this point, I made a simple demo application at https://github.com/TimPurdum/Mvvm. I started with the Visual Studio Blazor Template, which gives you three Blazor Pages:

  • Index(Home/Main) – with text and a link to a survey
  • Counter – with an interactive button that increments a number counter
  • FetchData – with a graph of weather data fetched from a “service” (mocked)

}

 

public void StartingWithBlazorAndMakingViewModels()

{

First, I created a new .Business project, and created a ViewModel for each of those pages. I used a very simple BaseViewModel and RelayCommand implementation, like Tim Jay and I discussed on the episode. Then I moved as much “logic” and content from the Blazor Pages to the ViewModels.

Image comparing original template with MVVM version
Left: Original Blazor template file; Right: MVVM refactor
Image comparing original template with MVVM version
Left: Original Blazor template file; Right: MVVM refactor
Image comparing original template with MVVM version
Left: Original Blazor template file; Right: MVVM refactor

Wow, I hate writing more code to accomplish the same task. But that’s only a temporary side-effect. Notice the use of binding via @ViewModel.Property in the Pages now. This makes our pages even more efficiently design-only, with the content being provided by the ViewModel.

}

 

public void AddingXamarinForms()

{

Next, I added the Visual Studio Xamarin.Forms template to the project. I chose the Master-Detail layout from the template selector, as this most closely resembles the Blazor/web layout.

The Xamarin.Forms template imports a class library, and individual executable projects for iOS, Android, and UWP (optional). The main focus of the Forms demo template is a Page with an editable list of items, that can be drilled into, edited, and refreshed. It also includes a nice About Page.

Now, the Xamarin.Forms template is already structured on MVVM, but uses a few Forms-specific things in their ViewModels. I wanted to move these to my Business project, but not introduce Xamarin.Forms dependencies that might conflict with my Blazor implementation.

Image compares Xamarin.Forms vs. Cross-platform implementation of Items view
Left: Xamarin.Forms ViewModel; Right: Cross Platform ViewModel

There were two major changes. First, the Xamarin.Forms BaseViewModel had a DataStore property. I decided to implement this just in ItemsViewModel, rather than in my own BaseViewModel, but either would have worked. Second, the original uses a Xamarin.Forms Command. I replaced this with my own RelayComand, and made the public Command property to be the common interface ICommand, which is .NET Standard. The ItemsPage.xaml and ItemsPage.xaml.cs required very little change at all, except setting Binding to the new ViewModel. I decided to inject the ViewModel and a reference to the IDataStore to make it possible to load and handle the NewItemPage.

I won’t bore you with the details of migrating NewItem, ItemDetail, and About. You should get the idea by now, and can certainly check out the code examples themselves.

After each refactor, I would run the Blazor or Forms app to make sure I hadn’t broken any functionality. I found many times that I did! Probably a nice Unit Test set around this project would be helpful as well, and I might add that in the future.

}

 

public void ImplementCrossPlatformViews()

{

The last main step was to implement Views(Pages) for the Blazor ViewModels in Xamarin.Forms, and the Forms ViewModels in Blazor. This is where it all pays off!

Xamarin Forms Implementations

HomePage.xaml
HomePage.xaml (Index/Main)
CounterPage.xaml
CounterPage.xaml
FetchDataPage.xaml
FetchDataPage.xaml

Blazor Implementations

About.razor
About.razor
ItemDetail.razor
ItemDetail.razor
Items.razor
Items.razor
NewItem.razor
NewItem.razor

}

 

public void Challenges()

{

There were several things that I discovered along the way that made implementation difficult.

Dependency Injection

Unfortunately, while both Xamarin.Forms and Blazor support DI, they don’t use the exact same implementation. Since the Blazor/Asp.Net Core version is now a .NET Standard Nuget Package, and appears poised to be baked into .NET 5, I went ahead and added this to the Forms project, so I could use the same references. But since the other DI is built into Forms, and they both use the IServiceProvider interface, I found some conflict with the .GetService<T> extension. I solved this by adding a local copy in the project of the same extension method, which then “won out” over the Forms extension.

Navigation

Navigation paradigms between mobile apps and web pages are very different. The web treats all links equally, whether to a local new page or a different site. Xamarin.Forms apps, on the other hand, keep their own internal list of pages (navigated by an enum/int), and then launch Chrome for external links. I solved this by creating a NavTarget class that included both a textual link and the MenuItemType enum. I’m sure there are more clever solutions to integrate these two together.

Fonts and Icons

This part took me a bit too long, and even so, I think there’s a bug in the UWP Xamarin.Forms renderer. The Blazor app makes use of icons from Open Iconic, which is really a font set. I thought it would be great to use this same open-sourced set for the Xamarin implementation. I discovered you can set the open-iconic.ttf file as an EmbeddedResource in the Xamarin.Forms project, and this should be able to be referenced. Like I said, it works for iOS/Android, but not for UWP.

}

 

public void NextSteps()

{

I’m hoping to take this pattern and apply it to some real projects in the future. I will keep you updated with new blog posts here. Be sure to join our mailing list, listen to our podcast, and leave a comment below on what you would like to see for future blog topics or podcast episodes. Also, if you have any suggestions for improving this demo project, feel free to leave comments here or on the github repository.

}

}