Here is another approach if you don't want to go with SignalR or WebSockets.
I have a Timer that dispatches on an interval as part of my Sprite component, to give you an example of how to do it:
The Sprite has a property called Subscriber
[Parameter]
public ISpriteSubscriber { get; set; }
The host component or page is an ISpriteSubscriber interface.
namespace DataJuggler.Blazor.Components.Interfaces
{
#region interface ISpriteSubscriber
/// <summary>
/// This interface is used by the AnimationManager to notifiy callers that a refresh occurred.
/// </summary>
public interface ISpriteSubscriber
{
#region Methods
#region Refresh()
/// <summary>
/// This method will call StateHasChanged to refresh the UI
/// </summary>
void Refresh();
#endregion
#region Register(Sprite sprite)
/// <summary>
/// This method is called by the Sprite to a subscriber so it can register with the subscriber, and
/// receiver events after that.
/// </summary>
void Register(Sprite sprite);
#endregion
#endregion
#region Properties
#region ProgressBar
/// <summary>
/// This is used so the ProgressBar is stored and available to the Subscriber after Registering
/// </summary>
ProgressBar ProgressBar { get; set; }
#endregion
#endregion
}
#endregion
}
Than in your razor code to set the parent, you set Subscriber=this:

Notice the Interval=50. This sets the timer to refresh every 50 milliseconds.
In the setter for my Sprite component, the first thing I do is call Register with the parent:
[Parameter]
public ISpriteSubscriber Subscriber
{
get { return subscriber; }
set
{
// set the value
subscriber = value;
// if the value for HasSubscriber is true
if (HasSubscriber)
{
// Register with the Subscriber so they can talk to each other
Subscriber.Register(this);
}
}
}
This code here is on the Index page that hosts the sprite, and Registers the Sprite with the parent:
public void Register(Sprite sprite)
{
// If the sprite object exists
if (NullHelper.Exists(sprite))
{
// if this is the RedCar
if (sprite.Name == "RedCar")
{
// Set the RedCar
RedCar = sprite;
}
else
{
// Set the WhiteCar
WhiteCar = sprite;
}
}
}
Now when my start race button is clicked, I start only 1 timer, I didn't want two timers running even though I have two cars:
public void StartRace()
{
// if both cars exist
if (NullHelper.Exists(RedCar, WhiteCar))
{
// Create a new instance of a 'RandomShuffler' object.
Shuffler = new RandomShuffler(2, 12, 100, 3);
// Start the timer on the RedCar
RedCar.Start();
}
}
Here is the Start method of the Sprite:
public void Start()
{
this.Timer = new Timer();
this.Timer.Interval = this.interval;
this.Timer.Elapsed += Timer_Elapsed;
this.Timer.Start();
}
And then the Timer_Elapsed event, calls the Subscriber to refresh:
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
// if a subscriber exists
if (HasSubscriber)
{
// Notify Subscriber
Subscriber.Refresh();
}
}
Now my refresh method is called every 50 milliseconds in this case, and I update my UI:
public void Refresh()
{
// do your updates
// Update the UI
InvokeAsync(() =>
{
StateHasChanged();
});
}
If you want to see a full working example, clone this project and look in the samples folder for the ProgressBarSample.
https://github.com/DataJuggler/DataJuggler.Blazor.Components
There is also a video here if you want to watch:
https://youtu.be/frtetHgfdIo
I have used this parent / child approach for a few things and it worked so well I wrote a blog post about it: Using Interfaces To Communicate Between Blazor Components
I find this is to be a good way to talk to other components or send data.
BlazorTimercomponent.