.NET MAUI Blazor - Best practices for Desktop UI
Tags: dotnet, desktop, webdev, css
Published: 2023-02-18 17:49:13

.NET MAUI Blazor is an open-source framework that lets you create cross-platform apps with web UI components and C# code. It uses BlazorWebView to render Razor components on mobile and desktop. So, like the [last article](https://dev.to/mhrastegari/net-maui-blazor-best-practices-for-mobile-ui-4def) which mostly was for mobile, this time I’m going to show you some handy tips for Desktop UI.


## Disable refresh with the `F5` key and zoom with the mouse wheel 
In your `MainPage.xaml` use the ` Loaded ` event of the `ContentPage` tag to override `BlazorWebView`’s default settings like the code down below:
```csharp
   public MainPage()
    {
        InitializeComponent();
        Loaded += ContentPage_Loaded;
    }

    private async void ContentPage_Loaded(object sender, EventArgs e)
    {
#if WINDOWS && RELEASE
        var webView2 = (blazorWebView.Handler.PlatformView as Microsoft.UI.Xaml.Controls.WebView2);
        await webView2.EnsureCoreWebView2Async();

        var settings = webView2.CoreWebView2.Settings;
        settings.IsZoomControlEnabled = false;
        settings.AreBrowserAcceleratorKeysEnabled = false;
#endif
    }
```

## Disable context menu
By default `Windows` context menu is disabled but `macOS` is not, so we need to disable it with a little bit of JavaScript in your `index.html` file:
```javascript
window.addEventListener('contextmenu', (event) => event.preventDefault());
```

## Change Windows Titlebar colors 
In the `Platforms/Windows/App.xaml` add these lines and change the colors to whatever you want.
```xml
<maui:MauiWinUIApplication
    x:Class="YouProject.Client.App.Platforms.Windows.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:maui="using:Microsoft.Maui">
    <maui:MauiWinUIApplication.Resources>
        <ResourceDictionary>
            <SolidColorBrush x:Key="WindowCaptionForeground">#512bdf</SolidColorBrush>
            <SolidColorBrush x:Key="WindowCaptionBackground">#ffffff</SolidColorBrush>
            <SolidColorBrush x:Key="WindowCaptionForegroundDisabled">#512bdf</SolidColorBrush>
            <SolidColorBrush x:Key="WindowCaptionBackgroundDisabled">#ffffff</SolidColorBrush>
        </ResourceDictionary>
    </maui:MauiWinUIApplication.Resources>
</maui:MauiWinUIApplication>
```
Learn more from [Microsoft documentation](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.window.settitlebar?view=windows-app-sdk-1.1#colors).

## Common HTML/CSS tricks

**1. Disable dragging images and selecting texts**
Well, I guess we all agree that not every image should be draggable also not every text should be selected so all you need to add these:
```scss
*:not(input) {
    user-select: none;
    -webkit-user-drag: none;
    -webkit-user-select: none;
}
```

**2. Have some tooltips**
Remember tooltips in developing desktop apps? You can do it with the `title` attribute on any `HTML` element.
For example:
```html
<button class="close-button" title="Close" @onclick="Close()"></button>
```

**3.  Change mouse cursor**
For different elements and components the mouse cursor can be changed, here is an example of using the `cursor` property to change the cursor to a pointer when hovering over a `div` tag with the class of `item`:
```scss
.item {
    cursor: pointer;
}
```

**4. Add some active and hover effects**
By default in some of the Native controls there are some hover and active(click) effects that change the color, So we can do it on the web like this:
```scss
  .item {
       background-color: white;
    }

  .item:active {
       background-color: whitesmoke;
    }

  .item:hover {
       background-color: lightgray;
    }
```

## Get window size
Sometimes you need to have the window size to do some calculations in your C# code so you can do it with JavaScript like this:

In your Razor component add these lines of code
```csharp
public partial class YourComponent : ComponentBase
{
    public int WindowWidth { get; set; }
    private string _resizeEventListenerId = string.Empty;
    private DotNetObjectReference<YourComponent>? _dotnetObjectReference;

    [Inject] private IJSRuntime JSRuntime { get; set; } = default!;

    protected override async Task OnInitializedAsync()
    {
        _dotnetObjectReference = DotNetObjectReference.Create(this);
        await base.OnInitializedAsync();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await JSRuntime.InvokeVoidAsync("UpdateWindowWidth", _dotnetObjectReference);
            await InitWindowWidthListener();
        }

        await base.OnAfterRenderAsync(firstRender);
    }

    [JSInvokable]
    public void UpdateWindowWidth(int windowWidth)
    {
        WindowWidth = windowWidth;
        StateHasChanged();
    }

    private async Task InitWindowWidthListener()
    {
        _resizeEventListenerId = Guid.NewGuid().ToString();
        await JSRuntime.InvokeVoidAsync("AddWindowWidthListener", _dotnetObjectReference, _resizeEventListenerId);
    }
}


```

And put these in a JavaScript file and add it in your `index.html`
```javascript
let windowEventListeners = {};

function AddWindowWidthListener(objReference, id) {
    let eventListener = () => UpdateWindowWidth(objReference);
    window.addEventListener("resize", eventListener);
    windowEventListeners[id] = eventListener;
}

function RemoveWindowWidthListener(id) {
    window.removeEventListener("resize", windowEventListeners[id]);
    delete windowEventListeners[id];
}

function UpdateWindowWidth(objReference) {
    objReference.invokeMethodAsync("UpdateWindowWidth", window.innerWidth);
}
```

---


Well, I guess it would be better to have both Mobile and Desktop best practices in one project, So I updated the sample repo containing all of the code that we discussed. You can have it [from here](https://github.com/mhrastegari/MauiBlazorUIBestPractices).

Happy coding ;D