Categle
Categle

Reputation: 514

Method blocking UI thread

I have recently created a helper method to throttle the speed of property changed event in order to save the data to my local database with a given delay. The only problem I got with it is that the method is apparently not running asynchronously and blocking my UI thread.

To test it, I have attached the event in my SettingsViewModel to the PercentageSliderViewModel:

public class SettingsViewModel : BaseVM
{
    public PercentageSliderViewModel Activity { get; set; }

    [...]

    public SettingsViewModel() {
        Activity.PropertyChanged += CreateThrottledCallback(Save, 1000);
    }

    [...]

    public async Task Save()
    {
        // Save data
    }
}

This is my helper method:

public PropertyChangedEventHandler CreateThrottledCallback(
            Func<Task> callback, int throttle = 1000)
{
    bool throttling = false;
    bool callFinal = false;

    return async(s, e) =>
    {
        if (throttling)
        {
            callFinal = true;
            return;
        }

        throttling = true;

        await callback?.Invoke();

        await Task.Delay(throttle).ContinueWith(_ => throttling = false);

        if (callFinal)
        {
            await callback?.Invoke().ContinueWith(_ => callFinal = false);
        }
    };
}

Even though the throttling is working fine, when I move the slider from left to right and the callback occurs it is 'freezing' for a small amount of time.

Debugging shows that it is running on the UI thread.

How can run CreateThrottledCallback method asynchronously so it wont block my main thread then?

Upvotes: 1

Views: 722

Answers (2)

mm8
mm8

Reputation: 169160

It's unclear what your Save method really does and whether it's actually a truly asynchronous method. You could try to execute it an a background thread in your CreateThrottledCallback method:

if (callback != null)
    await Task.Run(() => callback.Invoke());

Upvotes: 1

vendettamit
vendettamit

Reputation: 14677

As it has nothing to do with UI, you can use ConfigureAwait(false). This will avoid capturing the current synchronization context and the task will run on TaskScheduler.Default thread pool context.

await callback().ConfigureAwait(false);

Upvotes: 0

Related Questions