Must create DependencySource on same Thread as the DependencyObject
Solution 1
I encountered a similiar situation.
I bound an ObservableCollection of a class named Person to a datagrid, and Person.SkinColor is SolidColorBrush.
What I did was the following:
foreach (Person person in personData)
{
PersonModel person= new Person( );
......
personModel.SkinColor = new SolidColorBrush(person.FavoriteColor);
personModel.SkinColor.Freeze();
.....
}
Solution 2
Just a guess, but Tasks get created on a background thread, by default. Try creating your task using the Task.Factory overload with a SynchronizationContext. I'm not sure if using the Dispatcher inside a Task works the way one would expect.
var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, uiContext);
Once you do that, you should be able to modify your backing property without using the dispatcher.
Solution 3
For the sake of completeness I'd mention that the approved answer doesn't suit if you've got some objects that doesn't inherit Freezable class. The standard ObservableCollection only allows updates from the dispatcher thread, so you need a thread-safe analog. There are two solutions of WPF guru Dean Chalk what solve the problem:
- Create a thread-safe observable collection. It's an old school solution that just works. To get the source code check a short article in his blog.
- Use Reactive Extensions library. See this article for an example. It's a bit bulky for one task, but meanwhile it brings a bunch of modern tools which come in handy.
UPDATE (31 July 2015):
Links to Dean Chalk's blog are dead, so here are alternatives:
- Thread-safe observable collection: article, source code.
- Multi-threading, ObservableCollection, Reactive Extensions: article.
Solution 4
Is your data source a DependencyObject? If so, it needs to be created on the UI thread, too. Usually, you shouldn't need to inherit your datasource from DependencyObject though.
Admin
Updated on July 09, 2022Comments
-
Admin almost 2 years
I bind observable dictionary from view model to view. I use Caliburn Micro Framework.
View:
<ListBox Name="Friends" SelectedIndex="{Binding Path=SelectedFriendsIndex,Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding Path=SelectedFriend, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" Style="{DynamicResource friendsListStyle}" IsTextSearchEnabled="True" TextSearch.TextPath="Value.Nick" Grid.Row="2" Margin="4,4,4,4" PreviewMouseRightButtonUp="ListBox_PreviewMouseRightButtonUp" PreviewMouseRightButtonDown="ListBox_PreviewMouseRightButtonDown" MouseRightButtonDown="ListBox_MouseRightButtonDown" Micro:Message.Attach="[MouseDoubleClick]=[Action OpenChatScreen()]" >
Code from view model class.
Properties look like this:
public MyObservableDictionary<string, UserInfo> Friends { get { return _friends; } set { _friends = value; NotifyOfPropertyChange(() => Friends); } }
In Dispatcher timer I call every 3 seconds in seperate thread new service method.
So I constructor of view model I have this:
_dispatcherTimer = new DispatcherTimer(); _dispatcherTimer.Tick += DispatcherTimer_Tick; _dispatcherTimer.Interval = TimeSpan.FromSeconds(3); _dispatcherTimer.Start(); _threadDispatcher = Dispatcher.CurrentDispatcher;
And Timer tick method is here:
private void DispatcherTimer_Tick(object sender, EventArgs eventArgs) { new System.Threading.Tasks.Task(() => { //get new data from server MyObservableDictionary<string, UserInfo> freshFriends = _service.GetFriends(Account); _threadDispatcher.BeginInvoke((System.Action)(() => { //clear data, Friend is property which is binded on listobox control Friends.Clear(); //here is problem - > refresh data foreach (var freshFriend in freshFriends) { Friends.Add(freshFriend); } })); }).Start();
when I run app I get this error:
Must create DependencySource on same Thread as the DependencyObject. at System.Windows.Markup.XamlReader.RewrapException(Exception e, Uri baseUri) at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlReader templateReader, XamlObjectWriter currentWriter) at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlObjectWriter objectWriter) at System.Windows.FrameworkTemplate.LoadOptimizedTemplateContent(DependencyObject container, IComponentConnector componentConnector, IStyleConnector styleConnector, List`1 affectedChildren, UncommonField`1 templatedNonFeChildrenField) at System.Windows.FrameworkTemplate.LoadContent(DependencyObject container, List`1 affectedChildren) at System.Windows.StyleHelper.ApplyTemplateContent(UncommonField`1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate) at System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container) at System.Windows.FrameworkElement.ApplyTemplate() at System.Windows.FrameworkElement.MeasureCore(Size availableSize) at System.Windows.UIElement.Measure(Size availableSize) at System.Windows.Controls.Border.MeasureOverride(Size constraint)
I try replace dispatcher:
this
_threadDispatcher = Dispatcher.CurrentDispatcher;
with this:
_threadDispatcher = Application.Current.Dispatcher;
But it doesn’t help. Thank for advice.
MyObservableDicionary is not dependency object or have dependecy property:
public class MyObservableDictionary<TKey, TValue> : IDictionary<TKey, TValue>, INotifyCollectionChanged, INotifyPropertyChanged {..}
-
Admin over 13 yearsWhat do you mean with data source ? Property Friend?
-
Botz3000 over 13 yearsYour view model, or anything that is bound to the UI.
-
Admin over 13 yearsNo, VM is create with Caliburn Micro, in this class I haven’t any dependecy properties and objects.
-
Botz3000 over 13 yearsMaybe your ObservableDictionary? Try creating that on the UI thread.
-
Admin over 13 yearsI try init variable freshFriends out of scope dispatcherTimer_tick event, in constructor of VM. But problem is same. MyObservable dic is ok in my view, no dependency property or object in this class.
-
RobV almost 9 yearsGreat answer - yes this approach does work, solved a problem I'd been hitting my head against for far too long.
-
JumpingJezza almost 9 yearsyour link is ded ;( Perhaps you could copy the information here instead of linking elsewhere?
-
Alex Klaus almost 9 years@JumpingJezza, I added alternative links. Both solutions are too bulky for a post.
-
JumpingJezza almost 9 yearsNot to worry. I had an Observable Collection of type ImageSource and simply freezing the ImageSource worked.
-
smerlung over 7 yearsI had the same problem with an ImageSource. Calling Freeze() also worked in my case
-
FindOutIslamNow about 7 yearsBut this does not execute the task in background anymore, right? it becomes an on-ui-operation.