I am trying to change a string, being used for a title, in my blazor-server-side application. But I am having trouble getting the UI to update.
I tried using StateHasChanged(), but that didn't work so I looked around and found that on the FlightFinder Demo that was made, it has an OnChange event Action, so I am trying to implement that.
It works until I try to refresh the browser, then I am hit with this error
System.InvalidOperationException: 'The current thread is not associated with the renderer's synchronization context. Use Invoke() or InvokeAsync() to switch execution to the renderer's synchronization context when triggering rendering or modifying any state accessed during rendering.'
This is what I have:
private string _title = "TestSite";
public string Title => _title;
public event Action OnChange;
public void ChangePage(string pageName)
{
_title = pageName;
NotifyStateChanged();
}
private void NotifyStateChanged(int navigationType = 0)
{
OnChange?.Invoke();
}
All I have to do is call ChangePage("some Page Title") and it works, unless as I mentioned I try to refresh.
I am just trying to change a string on one component that through another component, which doesn't sound all that crazy. If there is a better way to do titles or change things from other components, I would love to hear about it.
So, what can I do to make sure that m invoke method is on the correct thread? Or is there a different way to change the title that would be more effective?
Thank you in advance!
I have just implemented a State Container like this and ran into the same error - but my service needs to be a singleton. So I found an example on the aspnetcore git that does exactly what the error message says to do. Call InvokeAsync -- not from your state container but when you try to change the state of your razor component.
https://github.com/dotnet/aspnetcore/blob/321db9d99f84cf7a67d453384292d9339de748d1/src/Components/test/testassets/BasicTestApp/DispatchingComponent.razor
So your state container doesn't need to change, just your component event handler does.
@code{
protected override void OnInitialized()
{
_YourService.OnChange += OnMyChangeHandler;
}
public void Dispose()
{
_YourService.OnChange -= OnMyChangeHandler;
}
private async void OnMyChangeHandler(object sender, EventArgs e)
{
// InvokeAsync is inherited, it syncs the call back to the render thread
await InvokeAsync(() => {
DoStuff();
StateHasChanged();
});
}
}
Now your service (if it's a singleton) can notify ALL your users at once! Think about all hoops we had to jump through in past to do this.
I posted this first thing in the morning thinking that I wouldn't have the time to look into and thinking that by time someone was able to help me out, I would have found the time to look into it more. Though I have spent a couple of days going back and forth on this already.
I finally found this article that explains that what I am trying to do is called a State Container.
What they said is that I could inject the class as a singleton, which is what I was doing or a scoped service. Turns out all I needed to do was change it to a scoped service and it works great!
no need sophisticated solution, Blazor working perfectly if you will update GUI in your event handler by
this.InvokeAsync(() => this.StateHasChanged());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With