首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >必须在与DependencyObject相同的线程上创建DependencySource

必须在与DependencyObject相同的线程上创建DependencySource
EN

Stack Overflow用户
提问于 2011-01-14 19:56:57
回答 4查看 31.6K关注 0票数 17

我将可观察字典从视图模型绑定到视图。我使用Caliburn微框架。

视图:

代码语言:javascript
运行
复制
    <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()]" >

视图模型类中的代码。

属性如下所示:

代码语言:javascript
运行
复制
public MyObservableDictionary<string, UserInfo> Friends
{
    get { return _friends; }
    set
    {
        _friends = value;
        NotifyOfPropertyChange(() => Friends);
    }
}

在调度定时器中,我每隔3秒调用一次独立线程的新服务方法。

所以我的视图模型的构造器我有:

代码语言:javascript
运行
复制
        _dispatcherTimer = new DispatcherTimer();
        _dispatcherTimer.Tick += DispatcherTimer_Tick;
        _dispatcherTimer.Interval = TimeSpan.FromSeconds(3);
        _dispatcherTimer.Start();

        _threadDispatcher = Dispatcher.CurrentDispatcher;

Timer tick方法如下:

代码语言:javascript
运行
复制
    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();

当我运行app时,我得到了这个错误:

代码语言:javascript
运行
复制
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)

我尝试替换dispatcher:

_threadDispatcher = Dispatcher.CurrentDispatcher;

有了这个:_threadDispatcher = Application.Current.Dispatcher;

但这并不管用。谢谢你的建议。

MyObservableDicionary不是依赖对象或具有依赖属性:

代码语言:javascript
运行
复制
public class MyObservableDictionary<TKey, TValue> :
    IDictionary<TKey, TValue>,
    INotifyCollectionChanged,
    INotifyPropertyChanged
{..}
EN

回答 4

Stack Overflow用户

发布于 2013-11-14 13:28:51

我遇到了类似的情况。

我将一个名为Person的类的ObservableCollection绑定到一个datagrid,而Person.SkinColor是SolidColorBrush。

我所做的事情如下:

代码语言:javascript
运行
复制
foreach (Person person in personData)
{
 PersonModel person= new Person( );
 ......               
 personModel.SkinColor = new SolidColorBrush(person.FavoriteColor);
 personModel.SkinColor.Freeze();
 .....
}
票数 29
EN

Stack Overflow用户

发布于 2011-01-15 05:26:02

这只是一个猜测,但默认情况下,任务是在后台线程上创建的。尝试使用带有SynchronizationContext的Task.Factory重载创建任务。我不确定在Task中使用Dispatcher是否会像人们期望的那样工作。

代码语言:javascript
运行
复制
var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, uiContext);

一旦你这样做,你应该能够修改你的支持属性,而不是使用调度程序。

票数 22
EN

Stack Overflow用户

发布于 2013-08-23 08:09:47

为了完整起见,我要提到的是,如果你有一些对象没有继承Freezable类,那么认可的答案就不适合你。标准ObservableCollection只允许来自dispatcher线程的更新,因此您需要一个线程安全的模拟器。WPF大师Dean Chalk有两种解决方案可以解决这个问题:

  1. 创建线程安全的可观察集合。这是一种老式的解决方案,很管用。要获得源代码,请查看short article in his blog.
  2. Use Reactive Extensions库。有关示例,请参阅this article。对于一项任务来说,它有点笨重,但同时它带来了一堆有用的现代工具。--

更新(2015年7月31日):

到Dean Chalk博客的链接已经死了,所以这里有一些替代方案:

  • 线程安全的可观察集合:article
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4690781

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档