6

I'm currently using MudBlazor and really like it.

However, there are things I find myself repeatedly adding to components like CancellationTokens, are customizing the template myself.

Is there a way to completely inherit/extend an existing component?

One option is to make a new component that has an instance of the component I want to modify, and to add all of the parameters to my component and map them back to the original, but I feel there has got to be a better way.

Tom Crosman
  • 1,137
  • 1
  • 12
  • 37
  • You can add methods through extension, but you can't add properties. You can create your own child components from the MudBlazor components, and then use those. But you probably want to add your stuff higher up the inheritance tree which isn't possible. You can always create your own custom MudBlazor library (if MudBlazor allow it). – MrC aka Shaun Curtis Jul 30 '22 at 15:56
  • 2
    There is no simple way to extend a component in Blazor - in the sense that you inherit the rendering but get to tinker with the logic. The only way is to wrap the component inside another and use it - similar to decorator pattern. You can do it more efficiently by abstracting the repeating logic into a class and providing the instance of that through a service/creating in the decorator component. – Mayur Ekbote Aug 12 '22 at 07:46
  • 1
    @MayurEkbote thanks. that was actually what i needed to hear. i was trying to force inheritance which wasn't working. composition also seems like the way to go when you want to combine multiple components into 1 – symbiont Apr 07 '23 at 09:49

4 Answers4

4

Attribute splatting is really handy for creating wrappers or higher level abstractions around other components:

<MudTextField Variant="@Variant" @attributes="@OtherAttributes"></MudTextField>

@code {
    [Parameter(CaptureUnmatchedValues = true)]
    public Dictionary<string, object> OtherAttributes { get; set; }

    [Parameter]
    // can even set your own defaults
    public Variant Variant { get; set; } = "Variant.Filled"
}

You can also create your own base components and use @inherits for shared logic and parameters.

Brandon Pugh
  • 1,567
  • 1
  • 13
  • 18
2

You can inherit blazor components like any other non-sealed class

using Microsoft.AspNetCore.Components;
using MudBlazor;

namespace MyMudBlazor;
public partial class MyMudButton : MudButton
{
    [Parameter] public bool IsEnabled
    {
        get { return !base.Disabled; }
        set { base.Disabled = !value; }
    }
}
Pawel
  • 891
  • 1
  • 9
  • 31
2

Inheritance

It sounds like you most likely want to @inherit the MudBlazor component in a new component of your own. This essentially allows you to use the MudBlazor component as a base class for your new class/component, avoiding having to redefine all of the parameters that the MudBlazor component already defines.

This can be done in C# or razor. Here's a razor example, OutlinedMudButton.razor, that allows the user to still set all of the usual MudButton parameters, except for the Variant parameter:

@inhertis MudButton

@code {
  // Hide the MudButton's Variant parameter so it can not be changed by users.
  protected new Variant Variant { get; set; }

  protected override void OnInitialized()
  {
    base.OnInitialized();
    base.Variant = Variant.Outlined;
  }
}

This blog post shows a complete example of how to inherit a component to extend it, change default parameter settings, add new UI elements to it, hide/disable parameters of the base component, and potentially change its functionality. If you want to add new UI elements around the component, you can use the following line of code to display the base component that you are inheriting from, placing the new UI elements around it.

@{
    // Display the base component that we are inheriting from.
    base.BuildRenderTree(__builder);
}

Composition

Depending on your use case, you may want to go with composition instead of inheritance, by creating a new component that simply contains an instance of the MudBlazor component that you want to decorate. This may be easier or more appropriate, especially if you want to hide many of the MudBlazor component's parameters so that users are not able to change them. Be aware that if you use attribute splatting as suggested in other answers/comments, the downside is your component will not provide editor intellisense for all of the MudBlazor component's parameters.

Here is another razor example, OutlinedMudButton.razor, that creates a component with an Outlined MudButton where the only thing the user can set is the button Text:

<MudButton Variant="Variant.Outlined">@Text</MudButton>

@code {
  [Parameter]
  public string Text { get; set;}
}
deadlydog
  • 22,611
  • 14
  • 112
  • 118
  • Important note about calling `base.BuildRenderTree(__builder)`, you cannot do it in a RenderFragment (i.e. wrapped in another component). For a solution see [this answer](https://stackoverflow.com/a/61970124/10534901) – Conman_123 Jul 27 '23 at 07:27
0

One shortcut I often use is to create a .razor component with no markup. It consumes whatever services I want, adds event handlers, and so on. So instead of inheritance, I have a drag-in sub-component that handles business logic. If it also has methods, then I add an @ref to the Component's markup. Many of my pages look like this:

<FontSizeUtility UserId = @UserId />
<TimerUtility @ref=MyTimer TimerTicker = HandleTimerTick />

@code{
     TimerUtility MyTimer = new();

. . . 
    async Task HandleTimerTick(){
    }

}
Bennyboy1973
  • 3,413
  • 2
  • 11
  • 16