【问题标题】:Portable Class Library and ObservableCollection, updating UI Thread可移植类库和 ObservableCollection,更新 UI Thread
【发布时间】:2014-02-04 03:11:41
【问题描述】:

我对这个话题不是很有经验,如果不是很清楚,请原谅我。

我创建了一个可移植类库,其中包含一个 ObservableCollection 部分,每个部分都有一个 ObservableCollection 项。

这两个集合都绑定到单独的 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?

非常感谢!

【问题讨论】:

    标签: observablecollection portable-class-library


    【解决方案1】:

    很难说没有看到其余的代码,但我怀疑这与可移植类库有什么关系。最好查看有关异常的详细信息(类型、消息和堆栈跟踪)。

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

    顺便说一句:我没有明确传递SynchronizationContext。我假设 ViewModel 是在 UI 线程上创建的。这让我可以像这样捕捉它:

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

    【讨论】:

    • 当我这样做时,上下文返回 null。我必须从应用程序中执行 new SynchronizationContext() 以获取要传入的值。奇怪的是它不会立即给我异常。它运行了几次,然后在相同类型的数据上给我那个错误。但我最终放弃并将绑定从数据源直接移动到视图模型中,我相信这是它们应该去的地方
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      您收到“在不同线程上编组”错误的原因是您没有将要添加到列表中的项目作为 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 中正常工作。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-13
        • 1970-01-01
        相关资源
        最近更新 更多