Reputation: 581
I have some problems with thread synchronization in my Templated control (trying to do a AutoComplete control)
Inside my control I have this code:
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();
var searchTextBox = GetTemplateChild("SearchTextBox") as TextBox;
if (searchTextBox != null)
{
var searchDelegate = SearchAsync;
Observable.FromEventPattern(searchTextBox, "TextChanged")
.Select(keyup => searchTextBox.Text)
.Where(TextIsLongEnough)
.Throttle(TimeSpan.FromMilliseconds(500))
.Do(ShowProgressBar)
.SelectMany(searchDelegate)
.ObserveOn(Dispatcher)
.Subscribe(async results => await RunOnDispatcher(() =>
{
IsInProgress = false;
SearchResults.Clear();
foreach (var result in results)
{
SearchResults.Add(result);
}
}));
}
}
And it is complaining that inside my ShowProgressBar method I'm trying to access code that was marshalled by another thread.
If I comment out the Throttle and the ObserveOn(Dispatcher) it works just fine, but it does not throttle my service calls as I want to.
If I only comment out the Throttle part, Nothing happens at all.
Upvotes: 0
Views: 295
Reputation: 74682
Asti's got the right idea, but a far better approach would be to provide the IScheduler
argument to Throttle instead:
// NB: Too lazy to look up real name
.Throttle(TimeSpan.FromMilliseconds(500), CoreDispatcherScheduler.Instance)
This will make operations below it happen on the UI thread (including your ShowProgressBar), up until the SelectMany.
Upvotes: 1
Reputation: 12687
Every dependency object requires that any changes to dependency properties be made only on the Dispatcher thread. The Throttle
is using a different scheduler, hence making any changes to the UI in a subsequent Do
combinator would result in an access exception.
You can resolve this by:
.Do(() => Dispatcher.Invoke(new Action(ShowProgressBar)))
Upvotes: 1