18

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

看法:

    <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()]" >

来自视图模型类的代码。

属性如下所示:

public MyObservableDictionary<string, UserInfo> Friends
{
    get { return _friends; }
    set
    {
        _friends = value;
        NotifyOfPropertyChange(() => Friends);
    }
}

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

所以我的视图模型构造函数我有这个:

        _dispatcherTimer = new DispatcherTimer();
        _dispatcherTimer.Tick += DispatcherTimer_Tick;
        _dispatcherTimer.Interval = TimeSpan.FromSeconds(3);
        _dispatcherTimer.Start();

        _threadDispatcher = Dispatcher.CurrentDispatcher;

Timer tick 方法在这里:

    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();

当我运行应用程序时,出现此错误:

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)

我尝试更换调度员:

这个 _threadDispatcher = Dispatcher.CurrentDispatcher;

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

但这无济于事。感谢您的建议。

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

public class MyObservableDictionary<TKey, TValue> :
    IDictionary<TKey, TValue>,
    INotifyCollectionChanged,
    INotifyPropertyChanged
{..}
4

4 回答 4

29

我遇到了类似的情况。

我将名为 Person 的类的 ObservableCollection 绑定到数据网格,并且 Person.SkinColor 是 SolidColorBrush。

我所做的是以下内容:

foreach (Person person in personData)
{
 PersonModel person= new Person( );
 ......               
 personModel.SkinColor = new SolidColorBrush(person.FavoriteColor);
 personModel.SkinColor.Freeze();
 .....
}
于 2013-11-14T05:28:51.310 回答
23

只是猜测,但默认情况下,任务是在后台线程上创建的。尝试使用带有 SynchronizationContext 的 Task.Factory 重载来创建您的任务。我不确定在 Task 中使用 Dispatcher 是否按预期的方式工作。

var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => { }, CancellationToken.None, TaskCreationOptions.None, uiContext);

一旦你这样做了,你应该能够在不使用调度程序的情况下修改你的支持属性。

于 2011-01-14T21:26:01.910 回答
4

为了完整起见,我会提到,如果您有一些不继承Freezable类的对象,则批准的答案不适合。标准的 ObservableCollection 只允许从调度程序线程进行更新,因此您需要一个线程安全的类比。WPF 大师Dean Chalk有两种解决方案可以解决这个问题:

  1. 创建一个线程安全的可观察集合。这是一个老派的解决方案,只是有效。要获取源代码,请查看他博客中的一篇短文
  2. 使用反应式扩展库。有关示例,请参见本文。它对于一项任务来说有点笨重,但同时它带来了一堆派上用场的现代工具。

更新(2015 年 7 月 31 日):

Dean Chalk 博客的链接已经失效,所以这里有替代方案:

  • 线程安全的可观察集合:文章源代码
  • 多线程、ObservableCollection、响应式扩展:文章
于 2013-08-23T00:09:47.193 回答
3

您的数据源是 DependencyObject 吗?如果是这样,它也需要在 UI 线程上创建。通常,您不需要从 DependencyObject 继承数据源。

于 2011-01-14T12:25:08.487 回答