Month: December 2018

Let’s talk Blazor!

Let’s talk Blazor!

You may or may not have heard of WebAssembly, or the Mono Framework, but Microsoft is blending them to wonderful platform goodness, for the future of the web. So, you may never need to understand either to take full advantage.

Keep in mind these are all experimental bits, at the moment. You can learn more at Blazor.net

WebAssembly (Wasm) is a part of all major modern browsers. It is a binary format for execution in a browser’s controlled sand-box. It is meant to be an intermediate format and not written directly, but it can be. In general you compile from a high level language to Wasm. It serves a similar purpose to JavaScript, but is not intended to be a replacement for JavaScript. In my opinion will take a large bite out of JavaScript’s stranglehold on client code; especially with Microsoft’s help.

The Mono framework was started in 2004. The .NET framework and compilers were Windows only. The Mono open-source project implemented the .NET APIs, based on the same ECMA-335 open standard, that was implemented in the official .NET. This allowed compiling and running .NET code on non-Windows systems, such as Linux and MacOS.

Blazor is an experimental Single-page application (SPA) framework that combines C#, WebAssembly, and Mono to allow C# code to be compiled and run directly in the browser. The Mono framework is provided as WebAssembly. For now, at least, the browser will use Mono to interpret the client .NET dll’s; but the speculation is that the compiler will eventually minify and cross-compile the .NET dll’s directly to WebAssembly.

Blazor has a deployment mode that is coded in mostly the same way, but runs server-side. The Blazor code runs on the server, and only the view differences are sent to the browser, via a SignalR connection. This mode gives the same coding benefits, but since the Blazor client code runs on the server, delays between the browser and server can be seen. It also requires more server compute power. This deployment mode is scheduled to be released in .NET Core 3.0.

For a Blazor coding experiment we will use the client side mode, with some WebApi to get configuration data. I made a simple dashboard with widgets that are loaded via server configuration. The project is based on the Hosted Blazor template.

Widgets can be any Blazor component, but I kept my widgets all cards to keep a consistent look.

There is a simple widget that just takes it content as parameters

There is a countdown widget, that can either countdown to a date, or count from one date to another with progress

There is a life countdown, to tell you how many more days you have to an age

And for fun there is a bouncing ball demo on a canvas

This is a simple demo, so the Blazor widgets are compiled directly into the client app, using pages. The index page will request an array of WidgetSettings from the server’s WebApi

WidgetSettings[] widgets;
protected override async Task OnInitAsync()
{
    widgets = await Http.GetJsonAsync<WidgetSettings[]>("api/SampleData/widgets");
    StateHasChanged();
}

The server currently returns a fixed list of widget settings, but could easily be extended to store and load these settings by the user.

[HttpGet("[action]")]
public IEnumerable<WidgetSettings> widgets()
{
    var widgets = new[]
    {
        new WidgetSettings() {widget = "LifeCountdown", parameters =  {{"Header","Jim"},{"BirthDay""1970/1/1"}, { "EndAge"70 }}},
        new WidgetSettings() {widget = "LifeCountdown", parameters =  {{"Header","Bob"},{"BirthDay""1990/7/4"},{ "EndAge"75 }}},
        new WidgetSettings() {widget = "LifeCountdown", parameters =  {{"Header","Rick"},{"BirthDay""1985/4/27"},{ "EndAge"80 }}},
        new WidgetSettings() {widget = "SimpleCard", parameters = {{"Header""This is a simple card"}, {"SubHeader"""},
            { "Body","This is the body of my simple card.  There are other simple cards, but this is mine."},
            { "colsLarge"6}, {"colsSmall"12}}},
        new WidgetSettings() {widget = "Countdown", parameters =
        {
            {"Header","Countdown to New Year" },
            {"From",$"{DateTime.Today.Year}/1/1"},
            {"To"$"{DateTime.Today.Year+1}/1/1"}
        }},
        new WidgetSettings() {widget = "Countdown", parameters =
        {
            {"Header","Countdown to July 4th" },
            {"From",$"{DateTime.Today.Year}/7/4"},
            {"To"$"{DateTime.Today.Year+1}/7/4"}
        }},
        new WidgetSettings() {widget = "CanvasWidget"}
    };
    return widgets;
}
 

These widgets are loaded to the Index page by using the builder, at runtime.

RenderFragment CreateDynamicComponent() => builder =>
{
    if (widgets == nullreturn;
 
    var assm = Assembly.GetExecutingAssembly();
    var assmName = assm.GetName().Name;
 
    foreach (var widget in widgets)
    {
        var widgetType = Type.GetType($"{assmName}.Widgets.{widget.widget}");
        if (widgetType != null)
        {
            AddWidget(builder, widgetType, widget.parameters);
        }
    }
};
 
private static void AddWidget(RenderTreeBuilder builder, Type widget, Dictionary<string,object> parameters )
{
    var seq = 0;
    builder.OpenComponent(seq, widget);
    foreach (var param in parameters)
    {
        seq++;
        builder.AddAttribute(seq, param.Key, param.Value);
    }
    builder.CloseComponent();
}

You can download the sample code here: https://github.com/jchristman75/BlazorDash

Let’s keep it simple – SimpleCommand

Let’s keep it simple – SimpleCommand

Another important part of the MVVM (Model-View-ViewModel) pattern is the allowing the View to request actions in the ViewModel.  We will achieve this with the ICommand Interface.

You can implement many single-purpose classes that implement ICommand, but as a good friend once told me, if you want to find the easy way to do something, ask a lazy person to do it twice.

I like to create a SimpleCommand that implements ICommand, and accepts an Action in the constructor.

public class SimpleCommand : ICommand
{
    public event EventHandler CanExecuteChanged;
 
    private bool _canExecute=true;
    private Action<object> _method = null;
 
    public SimpleCommand(Action<object> method)
    {
        _method = method;
    }
 
    public void setCanExecute(bool canExecute)
    {
        _canExecute = canExecute;
        CanExecuteChanged?.Invoke(this,null);
    }
 
    public bool CanExecute(object parameter)
    {
        return _canExecute;
    }
 
    public void Execute(object parameter)
    {
        _method(parameter);
    }
}

With this SimpleCommand, the CanExecute state is manually set via the setCanExecute method, but you can easily pass a predicate in the constructor to validate CanExecute as well.  Keep in mind, this value should be very inexpensive or better yet cached, as some MVVM frameworks will exhaustively call the CanExecute method to see if the Command has changed states.

You can also extend the constructor to accept a default state for CanExecute, if that is desirable.

Add one of these commands to your ViewModel.

private SimpleCommand _simpleMessageCommand = null;
public SimpleCommand SimpleMessageCommand
{
    get
    {
        if(_simpleMessageCommand ==null)
        {
            _simpleMessageCommand = new SimpleCommand((x) => Message = x as string);
        }
    return _simpleMessageCommand;
    }
}

In this example Message sets a message to the Simple view

private string _message = "Hello World!";
public string Message
{
    get => _message;
    set => setBackingField(ref _message, value);
}

Most of the UI elements you are used to using, with Events, will have Dependency Properties that accept commands to be used in-place of the events.

For instance a button has a Command property that can replace the click event.

Bind to the Command. If you need to pass a parameter you can pass that in the Command’s associated Parameter property; or for advanced data bind to the Parameter.  The button will be enabled or disabled based on the CanExecute state of the Command.

<Button Content="Say 'Button Pressed'" Command="{Binding SimpleMessageCommand}" CommandParameter="Button Pressed"/>

Here is a simple view at startup.


Pressing the Say ‘Button Pressed’ Button, which is connected to our command, will execute the command.  The command will update the message, with the message passed through the parameter.

Let’s start simple – SimpleViewModelBase

Let’s start simple – SimpleViewModelBase

To implement the MVVM (Model-View-ViewModel) pattern, you need ViewModels that implement the INotifyPropertyChanged Interface.

I normally handle this by having a base class for all ViewModels to inherit.

public abstract class SimpleViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
 
    public void OnPropertyChanged([CallerMemberNamestring propertyName = "")
    {
        PropertyChanged?.Invoke(this,
                        new PropertyChangedEventArgs(propertyName));
    }
 
    public bool setBackingField<T>(ref T storage, 
                                   T value,
                                   [CallerMemberNamestring propertyName = "")
    {
        var oldValue = storage;
 
        if(object.Equals(storage, value))
        {
            return false;
        }
 
        storage = value;
 
        OnPropertyChanged(propertyName);
 
        return true;
    }
}

OnPropertyChanged() will either allow for a property to announce that it has changed

public string MyProperty
{
    get { return _myProperty; }
    set
    {
        _myProperty = value;
        OnPropertyChanged();
    }
}

..or that another property has changed, by passing the name of that property.

public string LastName
{
    set
    {
        ...
        OnPropertyChanged(nameof(FullName));
    }
}

setBackingField<T>() is a helper method to allow property setters to perform all of the aspect necessary for setting their backing field and calling OnPropertyChanged to reflect that change.

public string MyProperty
{
    get { return _myProperty; }
    set
    {
        setBackingField(ref _myProperty, value);
    }
}

setBackingField<T>() will return a boolean informing if there was change.

ViewModels will inherit this and take advantage of the helper methods

public class PersonViewModel : SimpleViewModelBase
{
    private string _firstName;
    public string FirstName
    {
        get => _firstName;
        set
        {
            if (setBackingField(ref _firstName, value))
            {
                //Also inform Fullname
                OnPropertyChanged(nameof(FullName));
            }
        }
    }
 
    private string _lastName;
    public string LastName
    {
        get => _lastName;
        set
        {
            if (setBackingField(ref _lastName, value))
            {
                //Also inform Fullname
                OnPropertyChanged(nameof(FullName));
            }
        }
    }
 
    public string FullName
    {
        get => $"{FirstName} {LastName}";
    }
}

console.writeline(“Hello world!”);

console.writeline(“Hello world!”);

Welcome to my blog experiment.  I have been a software developer for over 20 years, developing C, C++, VB, ASP, PHP.  In the past 14 years I have focused on .NET for desktop. 

The world is growing rapidly around me.  This blog will encourage me to grow my abilities, and if it helps someone else along the way, we both benefit