Reputation: 6232
I'm quite expierenced with WPF but there is one thing that bothers me. I'm using ReactiveUI for raising INotifyPropertyChanged events. I've got two places similiar to this:
public UiModel UiModel
{
get { return _uiModel; }
set { this.RaiseAndSetIfChanged(ref _uiModel, value); }
}
public void Run()
{
UiModel = GetUIModel();
}
where Run()
is called like this await Task.Run(()=>Run());
and UiModel
is bound in XAML
.
So what basically should happen -> it should throw a cross-threading exception if Run()
function is invoked on a different thread, shouldn't it? I've two places in the code and in one place it always throws an exception and in the second place exception is never thrown. I've compared thread IDs and in both places Run()
is run not on UI thread. Why is this the case?
In place where it doesn't throw exceptions I bind it to Dependency Property in UserControl and in the second place I bind it using normal binding
Exception being thrown: {"The calling thread cannot access this object because a different thread owns it."}
It looks like moreless I've found the answer for this specific situation. The exception is not thrown by UiModel and it's binding, but UiModel is also used in ReactiveUI validation. If I don't update it from UI it will try to update CanExecuteChanged from a different thread causing that exception. Nevertheless my question remains the same - why can I Update UI from a different thread without cross threading exception? I can't see dispatcher calls in ReactiveUI PropertyChanged invocation.
Upvotes: 4
Views: 2584
Reputation: 14322
There are some annoying inconsistencies in this area. Here is a list of actions that you can and can't perform from a worker thread.
Raises cross thread exception:
DependencyProperty
on a Control ICommand.CanExecuteChanged
eventINotifyCollectionChanged.CollectionChanged
event, commonly from an instance of ObservableCollection<T>
Does not throw an exception:
INotifyPropertyChanged.PropertyChanged
event, commonly from view model bindingI'm sure there is a good reason why WPF doesn't invoke the first list automatically but I can't think what it might be.
My recommendations for handling service events are:
SynchronizationContext
captures from the UI thread (probably the most use to you here).Upvotes: 4