Home > Back-end >  How to handle large number of "dialogs" without navigating away from the root component?
How to handle large number of "dialogs" without navigating away from the root component?

Time:09-28

Having an existing WinForms application that I'm migrating to .NET 6 with C# Blazor WebAssembly.

In this WinForms application there is one main window and let's say approximately 50 individual modal dialog box windows (which in turn sometimes show additional modal dialog box windows).

Steps in WinForms

In WinForms to show a dialog it was pretty straightforward:

  1. User clicks on a main menu item "Edit this thing".
  2. A C# click handler is called.
  3. In this click handler, I create an instance of my dialog box class.
  4. The instance is being shown.
  5. When the user closes the dialog box, the instance of the class goes out of scope and is later automatically cleaned up by the GC.

Steps in Blazor

Currently I cannot wrap my head around on how to adapt this concept to a WASM Blazor world.

In my planning I have one single "root" component ("Page") that does not change throughout the whole time that the user interacts with the application. This equals the "main window" concept in WinForms.

For each formerly WinForms dialog box window I plan to create one Blazor component (each with a DxPopup component that shows the form controls as a dialog box).

But I'm not sure on where and how to place these components.

Questions

  • Should I really place 50 components right in the root component and show/hide them as needed?
  • Should I have one single DynamicComponent component that I tell by code which actually component to render?
  • Any other options?

My fear is to get horrible performance when polluting the component tree with so much components in advance when all I really actually need is one component at a time.

CodePudding user response:

I believe good practice is to render only when it's needed.

When it comes to component based frameworks, you need to leverage off your components as much as possible. Dynamic components are amazing for this, and can really improve development speed.

I recommend not using dialogs/modals, bar special occasions. I see it being used a lot, and quite frankly, I believe it to be bad for user experience and performance. Only render what is needed at that time, especially in WASM since the client is doing all the UI computing.

In your instance I recommend starting with the basics as you work on this application, if done correctly, this foundation will improve your development speed 10 fold.

Need to put in a textbox? Create a component, and doing so you will learn the ins and outs of Blazor a lot quicker. You will also realise the dos and don'ts.

Ok now you have a textbox, next up is a form item to contain the textbox. Create a component for the form item.

Now you can wrap your textbox in a form item. So later, if you need to change anything, be it logic or CSS, you only need to update a single component.

Grow your component library from there, and with that your understanding of Blazor.

Now to the subject at hand: It is good to hide what isn't used. Wrap code blocks in if statements, and render them when needed. There's also no reason not to navigate to a new page. If you have a lot going on in a single page component, I recommend splitting what you have into smaller components. It's easier to work through, and a lot easier to maintain.

At the end of the day you can have:

@if (_showForm1) {
    <MyFormComponent Heading="Form 1">
        <MyFormItem Label="Value 1">
            <MyInputText @bind-Value="@form1.Value1" />
        </MyFormItem>
    </MyFormComponent>
}

Important note: Not every blazor component library is good. I ran across MatBlazor and I was astonished at the bad implementations within this library. It is an overcomplicated mess. It is open source on GitHub, so you can have a look.

Keep whatever you do as simple as possible. Don't make a component a jack of all trades. Your components must be very specific, and focused around performance. A generic component is not a jack of all trades component if it has a specific focus. Example, an input component for numeric values can be generic to support int, long, decimal etc. But an input component that can work with string, DateTime and int, is a jack of all trades. This should be obvious...but I've seen some things.

CodePudding user response:

As I mentioned in the comments, Blazored.Modal is a very powerful library for showing dialogs just-in-time by injecting an IModalService in your components, created by Chris Sainty. Example usage:

@inject IModalService Modal

<button @onclick="ShowFormBtnClicked">Show form</button>

@code {
    void ShowFormBtnClicked()
    {
        // FormDialog is a different component (FormDialog.razor).
        Modal.Show<FormDialog>("Form dialog title");
    }
}

You can also pass parameters to the dialogs and receive results from them (e.g. confirm dialog).

Documentation

This way each dialog is a separate component that is loaded only where and when it's needed. With this library you can avoid having to put all modals inside your components like that:

<Modal @bind-Visible="_modal1Visible">...</Modal>
<Modal @bind-Visible="_modal2Visible">...</Modal>
<Modal @bind-Visible="_modal3Visible">...</Modal>
...
...

@code {
    private bool _modal1Visible;
    private bool _modal2Visible;
    private bool _modal3Visible;
    ...
}
  • Related