Reputation: 514
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
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
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