Eto.Forms.TextBox with delay on TextChanged event

Good evening,

I am trying to implement a Eto.Forms.TextBox with slide delay in the TextChanged event as I dont want to update the TreeGridView on every single change, just after the input might have stopped.

I am using a System.Timers.Timer.

private void OnFilterTextBoxTextChanged(object sender, EventArgs e)
{
    try
    {
        if (sender is TextBox textBox &&
            textBox.Tag is int columnIndex)
        {
            this.TreeGridView.ViewModel.FilterColumnIndex = columnIndex;
            if (_typingDelayTimer == null)
            {
                _typingDelayTimer = new Timer
                {
                    Interval = 300,
                    Enabled = true,
                };
                _typingDelayTimer.Elapsed += new ElapsedEventHandler(this.OnTypingDelayTimerElapsed);
            }
            _typingDelayTimer.Stop(); // Resets the timer
            _typingDelayTimer.Start();
        }
    }
    catch (AFException ex)
    {
        AntFarmUtilities.DisplayAFException(ex);
    }
}

private void OnTypingDelayTimerElapsed(object source, ElapsedEventArgs e)
{
    if (source is Timer timer)
    {
        timer.Stop();
        // This code is executed in the wrong thread
        this.TreeGridView.ViewModel.FilterText = this.ViewModel.CurrentFilterText;
        this.TreeGridView.Filter();
    }
}

Well I am getting a Eto.Forms.UIThreadAccessException - not suprising, but how should I implemented something like this?

Any help as always is much appreciated.
Christian

Alright, found a solution (still open for suggestions :wink: )

using System.Threading;

In the constructor setting a local private System.Threading.Timer:

_typingDelayTimer = new Timer((c) => LoadData(), null, Timeout.Infinite, Timeout.Infinite);

In the TextChanged event I am changing the timer:

private void OnFilterTextBoxTextChanged(object sender, EventArgs e)
{
    try
    {
        if (sender is TextBox textBox &&
            textBox.Tag is int columnIndex)
        {
            this.TreeGridView.ViewModel.FilterColumnIndex = columnIndex;
            _typingDelayTimer.Change(300, Timeout.Infinite);
        }
    }
    catch (ObjectDisposedException ex)
    {
        AntFarmUtilities.DisplaySystemException(ex);
    }
    catch (ArgumentOutOfRangeException ex)
    {
        AntFarmUtilities.DisplaySystemException(ex);
    }
}

Once the timer is over it will load the method LoadData():

private void LoadData()
{
    Application.Instance.Invoke(delegate
    {
        this.TreeGridView.ViewModel.FilterText = this.ViewModel.CurrentFilterText;
        this.TreeGridView.Filter();
    });            
}

I was missing the Invoke, I guess.

Kindest
Christian

@Christian_Hartz,

Eto.Forms.UITimer is a UI-friendly timer that doesn’t rely on a background thread, nor requires an Invoke() that you can use for this purpose.

Let’s see if I can figure it out. :wink: I will give it a shot. Thanks once again. Christian