Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call a C# non static method from a static method in Blazor invoked by Javascript DotNet.invokeMethodAsync

I understand we can change a C# property value in Blazor from JavaScript by invoking the method DotNet.invokeMethodAsync. I have the below working but in this method I want to also call a non static method.

JS File:

[script.js]

function ChangeContentJS() {
    DotNet.invokeMethodAsync('InvokeFromJsApp', "ChangeParaContentValue", "New Content");
}

Razor page:

     [Index.razor]
    
    @page "/"
    
    @inject IJSRuntime JSRuntime
    
    <h1>Change C# property value from JavaScript</h1>
    <br />
    <button @onclick='ButtonClickHandler'>Change Content - JS</button>
    <br />
    <p>@ParaContent</p>
    
    @code {
        public static string ParaContent = "Some Text Content"; 

        public async Task ButtonClickHandler()
        {
            await JSRuntime.InvokeAsync<string>("ChangeContentJS");
        }
    
        [JSInvokable]
        public static void ChangeParaContentValue(string value)
        {
            ParaContent = value;
            RunNewCode(); //DOESNT WORK AS ITS A NON-STATIC METHOD
        }

        public void RunNewCode()
        {
           jsRuntime.InvokeVoidAsync("RunFunction");
        }
    }

I am trying to run a non static method in a static method (IN BLAZOR APPLICATION). How can I call this method?

I attempted to make the following method static and got the below error:

  public static void RunNewCode()
            {
               jsRuntime.InvokeVoidAsync("RunFunction");
            }

CS0120: An object reference is required for the nonstatic field, method, or property 'JSRuntime'

How do I make this static: @inject IJSRuntime JSRuntime

like image 907
RA19 Avatar asked Mar 22 '26 22:03

RA19


2 Answers

That's actually described in the docs

summery: create a static Action for the update and register the local instance

@implements IDisposable

...

private static Func<string, Task>? ChangeParaContentActionAsync;

private async Task LocalChangeParaContentValueAsync(string value)
{
    ParaContent = value;
    await jsRuntime.InvokeVoidAsync("RunFunction");
}

protected override void OnInitialized()
{
    base.OnInitialized();
    ChangeParaContentActionAsync = LocalChangeParaContentValueAsync;
}

// alas, no guarantees disposal works properly: this can even be called during initialization 
public void Dispose()
{
    ChangeParaContentActionAsync = null:
}

[JSInvokable]
public static async Task ChangeParaContentValue(string value)
{
    if (ChangeParaContentActionAsync is {} actionAsync)
    {
        await actionAsync(value);
    }
}

(not tested)

NOTE It is important to remember that you can still invoke the JSInvokable method even if the component is not loaded (i.e. no instance). This might infer undefined behavior!

edit: changed to async Task, due to the async InvokeVoidAsync method

like image 128
JHBonarius Avatar answered Mar 24 '26 13:03

JHBonarius


You can try this way. It seemed to work for me but I don't know if this is a good thing to do.

private static CurrentRazorComponentClassName _app;

public CurrentRazorComponentClassName ()
{
    _app = this;
}

[JSInvokable]
public static void MudaTextoNoBlazor(string texto)
{
    textojs = texto;
    contentEditable = false;
    _app.StateHasChanged();
}
like image 34
Ricardo Araújo Avatar answered Mar 24 '26 13:03

Ricardo Araújo