可移植类库和ObservableCollection,更新UI线程

时间:2013-04-27 18:30:58

标签: observablecollection portable-class-library

我对这个话题不太熟悉,请原谅我,如果不是很清楚。

我创建了一个可移植的类库,它有一个ObservableCollection的Sections,每个secion都有一个ObservableCollection of Items。

这两个集合都绑定到单独的Win8和WP8应用程序的UI。

我正在尝试找出正确填充这些集合的正确方法,以便从PCL类更新UI。

如果该类在win8项目中,我知道我可以执行类似Dispatcher.BeginInvoke的操作,但这不会转换为PCL,也不能在WP8项目中重用它。

在这个帖子(Portable class library equivalent of Dispatcher.Invoke or Dispatcher.RunAsync)中,我发现了SynchroniationContext类。

我传入了对主应用程序的SynchroniationContext的引用,当我填充这些部分时,我可以这样做,因为它只是一个对象正在更新:

if (SynchronizationContext.Current == _synchronizationContext)
{
    // Execute the CollectionChanged event on the current thread
    UpdateSections(sections);
}
else
{
    // Post the CollectionChanged event on the creator thread
    _synchronizationContext.Post(UpdateSections, sections);
}

然而,当我尝试用文章做同样的事情时,我必须引用部分和文章,但Post方法只允许我传入一个对象。

我试图使用lambda表达式:

if (SynchronizationContext.Current == _synchronizationContext)
    {
// Execute the CollectionChanged event on the current thread
    section.Items.Add(item);
}
else
{
    // Post the CollectionChanged event on the creator thread
    _synchronizationContext.Post((e) =>
    {
        section.Items.Add(item);
    }, null);
}

但我猜这不正确,因为我收到了关于“为不同线程编组”的错误。

那我在哪里错了?如何从PCL正确更新两个集合,以便两个应用程序也可以更新其UI?

非常感谢!

3 个答案:

答案 0 :(得分:2)

很难说没有看到其余的代码,但我怀疑是否与Portable Class Libraries有关。很高兴看到有关异常的详细信息(类型,消息和堆栈跟踪)。

使用多于参数调用Post()的方式看起来是正确的。如果您删除if检查并且只是总是通过SynchronizationContext.Post()会发生什么?

BTW:我没有明确传入SynchronizationContext。我假设在UI线程上创建了ViewModel。这允许我像这样捕获它:

public class MyViewModel
{
    private SynchronizationContext _context = SynchronizationContext.Current;
}

答案 1 :(得分:1)

我建议至少在您的ViewModel中,所有公开可观察的状态更改(即属性更改通知和对ObservableCollections的修改)都发生在UI线程上。我建议对模型状态更改做同样的事情,但让它们在不同的线程上进行更改并将这些更改封送到ViewModel中的UI线程可能是有意义的。

要做到这一点,当然,您需要能够在可移植代码中切换到UI线程。如果SynchronizationContext不适合您,那么只需为调度程序创建自己的抽象(即IRunOnUIThread)。

答案 2 :(得分:0)

您获得“在不同线程上编组”错误的原因是您没有将项目作为Post(action,state)方法上的“状态”对象添加到列表中。

您的代码应如下所示:

if (SynchronizationContext.Current == _synchronizationContext)
    {
// Execute the CollectionChanged event on the current thread
    section.Items.Add(item);
}
else
{
    // Post the CollectionChanged event on the creator thread
    _synchronizationContext.Post((e) =>
    {
        var item = (YourItemnType) e;
        section.Items.Add(item);
    }, item);
}

如果您进行了更改,您的代码将在PCL中正常运行。