Custom TypingStarted and TypingEnded Events

You know that little indicator in a chat that shows if someone is currently typing? I am working on a new post (coming soon, link will be here) that uses SignalR to communicate who is currently typing in a chat room along with the messages themselves.

To determine who is typing, I use a timer and the TextChanged event. The timer logic itself is straightforward, in the TextChanged event starts a timer.

  • The first TextChanged event starts a timer.
  • If the TextChanged event fires again before the timer’s Elapsed event, the timer is stopped and restarted.
  • If the Timer’s Elapsed event is fired first, then the user has stopped typing.

This code is a bit tedious to implement over and over again, so why not just build it into the control itself and invoke a custom TypingStarted and TypingEnded event? Enjoy!

public class TimedEntry : Entry, IDisposable
{
    private readonly System.Timers.Timer timer;

    public TimedChatEntry()
    {
        TextChanged += TimedChatEntry_TextChanged;

        timer = new System.Timers.Timer(1000);
        timer.Elapsed += timer_Elapsed;
    }

    public event EventHandler<EventArgs> TypingStarted;

    public event EventHandler<EventArgs> TypingEnded;

    private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs args)
    {
        if (timer == null)
            return;

        timer?.Stop();
        Device.BeginInvokeOnMainThread(() => TypingEnded?.Invoke(this, new EventArgs()));
    }

    private void TimedChatEntry_TextChanged(object sender, TextChangedEventArgs e)
    {
        if (timer == null)
            return;

        if (!timer.Enabled)
        {
            timer?.Start();
            Device.BeginInvokeOnMainThread(() => TypingStarted?.Invoke(this, new EventArgs()));
        }
        else
        {
            timer.Stop();
            timer.Start();
        }
    }

    public void Dispose()
    {
        if (timer != null)
        {
            timer.Elapsed -= timer_Elapsed;
        }
        timer?.Dispose();
    }
}

Here’s an example that uses a SignalR service:

<TimedEntry TypingStarted="TimedChatEntry_OnTypingStarted"
            TypingEnded="TimedChatEntry_OnTypingEnded"/>
private async void TimedChatEntry_OnTypingStarted(object sender, EventArgs e)
{
    if (service != null)
        await service.SendTyperAsync(me.Name, true);
}

private async void TimedChatEntry_OnTypingEnded(object sender, EventArgs e)
{
    if (service != null)
        await service.SendTyperAsync(me.Name, false);
}

You can see the entire thing in action, including the SignalR Hub project, here on GitHub: SignalR Chat Room Demo.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.