Search code examples
c#asp.net-coreblazor-server-side.net-7.0

Blazor Inherited Custom Components


I've done some simple stuff with Blazor but now I'm looking to do some more complex things and one that I would like to do is to build some custom components. Some of those components have common functionality so it makes sense to have that common functionality all in one place. Call that the BaseComponent. Using that BaseComponent I want to create a DerivedComponent that has all the functionality of the BaseComponent but adds something extra.

Here's where I'm having a problem. When I go to use the DerivedComponent on a page there seems to be no communication between the page and the BaseComponent, but the functionality of the BaseComponent is there. To try to figure things out I've created a BaseComponent like the Counter example in the default Blazor app. There's a button that increments a value and displays it and then calls the EventCallback saying that the value has changed. This never gets back to the page. Similarly at the page if I assign something to the DerivedComponent's functionality, that works, but anything that's assigned for the BaseComponent doesn't.

Here's the code, thanks for any help.

BaseComponent

<div>
    <div style="display: table-cell; vertical-align: top; padding: 0.25em;">
        <input type="text" readonly value="@Value"/>
    </div>
    <div style="display: table-cell; vertical-align: top; padding: 0.25em;">
        <input type="button" value="@Text" @onclick="Callback"/>
    </div>
</div>

@code {

    [Parameter] public string Text { get; set; } = string.Empty;
    [Parameter] public string Value { get; set; } = string.Empty;
    [Parameter] public EventCallback<string> ValueChanged { get; set; }


    private void Callback(MouseEventArgs obj)
    {
        if (string.IsNullOrWhiteSpace(Value))
            Value = "0";

        Value = (Convert.ToInt32(Value)+1).ToString();

        ValueChanged.InvokeAsync(Value);

    }

}

DerivedComponent

@using System.Diagnostics
@inherits BaseComponent;
<div style="color: @Color;">
    Derived:<br/> 
    <BaseComponent />
</div>

@code {

    [Parameter] public string Color { get; set; } = "red";

    protected override void OnParametersSet()
    {
        base.OnParametersSet();

        Debug.WriteLine($"Text: {Text}");
        Debug.WriteLine($"Value: {Value}");
    }

}

Page Code

@using System.Text
@page "/Test"
   
<PageTitle>Test</PageTitle>
   
<div style="padding:2em;">
    <DerivedComponent Color="blue" @bind-Value="@_parentChildText" Text="Click"></DerivedComponent>
</div>

<div>
    <input type="button" value="Dump Values" @onclick="CallbackDumpValues" />
</div>
<hr/>
<div>
    @((MarkupString)_markupString)
</div>

@code {

    private string _parentChildText = "1000";
    private string _markupString = string.Empty;

    private void CallbackDumpValues(MouseEventArgs obj)
    {

        StringBuilder sbMarkupString = new StringBuilder();


        sbMarkupString.AppendLine($"Dump From: {DateTime.Now}<br/><br/>");
        sbMarkupString.AppendLine($"_parentChildText: {_parentChildText}<br/>");

        _markupString = sbMarkupString.ToString();

    }

}

Solution

  • Change the DerivedComponent like below solved the problem:

    @inherits BaseComponent
    
    <div style="color: @Color;">
        Derived:<br />
        @RenderBase()
    
    </div>
    
    @code {
    
        [Parameter] public string Color { get; set; } = "red";
    
        protected override void OnParametersSet()
        {
            base.OnParametersSet();
    
            Console.WriteLine($"Text: {Text}");
            Console.WriteLine($"Value: {Value}");
        }
    
        RenderFragment RenderBase() => builder => base.BuildRenderTree(builder);
    }
    

    Test
    enter image description here