0

我正在使用 Reactive UI 为 Windows Phone 7.1 开发我的第一个应用程序,并且在使用 ReactiveCollection 类时遇到了困难。

我的应用程序大致是关于访问 WP7 SQL CE 引擎(LINQ to SQL)。我想使用 ReactiveAsyncCommand 在后台执行数据操作。来自数据库的数据应该“自动”出现在 UI 中,因此我决定使用 ReactiveCollection 作为数据库和 UI 之间的代理。

这是我的模型,所以你可以有一个更好的主意:

public class EncounteredModel
{
    public ReactiveCollection<Fact> FactsCollection;

    public ReactiveCollection<FactEntry> FactEntriesCollection;

    private EncounteredModel()
    {
        using (EncounteredDataContext db = new EncounteredDataContext())
        {
            FactsCollection = new ReactiveCollection<Fact>(from fact in db.Facts select fact);
            FactEntriesCollection = new ReactiveCollection<FactEntry>(from factEntry in db.FactEntries select factEntry);
        }

        FactsCollection.ItemsAdded.Subscribe(fact => { using (var db = new EncounteredDataContext()) { db.Facts.InsertOnSubmit(fact); db.SubmitChanges(); } });
        FactsCollection.ItemsRemoved.Subscribe(fact => { using (var db = new EncounteredDataContext()) { db.Facts.DeleteOnSubmit(fact); db.SubmitChanges(); } });

        FactEntriesCollection.ItemsAdded.Subscribe(factEntry => { using (var db = new EncounteredDataContext()) { db.FactEntries.InsertOnSubmit(factEntry); db.SubmitChanges(); } });
        FactEntriesCollection.ItemsRemoved.Subscribe(factEntry => { using (var db = new EncounteredDataContext()) { db.FactEntries.DeleteOnSubmit(factEntry); db.SubmitChanges(); } });
    }

    private static EncounteredModel instance;

    public static EncounteredModel Instance
    {
        get 
        {
            if (instance == null)
                instance = new EncounteredModel();
            return instance; 
        }
    }

}

在我的视图模型中,我尝试使用 2 种不同的变体:

  1. 创建派生的反应性集合并将 UI 绑定到它(使用 ReactiveCollection.CreateDerivedCollection() 方法。例如,它派生自 EncounteredModel.FactsCollection。
  2. 使用ObservableAsPropertyHelper<IEnumerable<Fact>>,然后订阅模型的 ReactiveCollection ChangedIObservable 来填充 OAPH。

不幸的是,这两种变体都给我“无效的跨线程访问”。两种变体的堆栈跟踪通常相同,这是变体 1 的堆栈跟踪(缩短为重要部分):

   at MS.Internal.XcpImports.CheckThread()
   at System.Windows.DependencyObject.GetValueInternal(DependencyProperty dp)
   at System.Windows.FrameworkElement.GetValueInternal(DependencyProperty dp)
   at System.Windows.DependencyObject.GetValue(DependencyProperty dp)
   at System.Windows.Controls.ItemsControl.get_ItemsHost()
   at System.Windows.Controls.ItemsControl.OnItemsChangedHandler(Object sender, ItemsChangedEventArgs args)
   at System.Windows.Controls.ItemContainerGenerator.OnItemAdded(Object item, Int32 index, Boolean suppressEvent)
   at System.Windows.Controls.ItemContainerGenerator.System.Windows.Controls.ICollectionChangedListener.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args)
   at System.Windows.Controls.WeakCollectionChangedListener.SourceCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
   at System.Windows.Controls.ItemCollection.NotifyCollectionChanged(NotifyCollectionChangedEventArgs e)

当我更改为 ReactiveCommand(不是异步命令)时,一切都很好。任何想法如何克服这个问题?非常感谢提前。

4

1 回答 1

0

ReactiveCollection 不会将所有内容代理到 UI 线程,如果您从工作线程向其中添加项目,您将在同一线程上向 UI 发出信号并导致崩溃。

但是,ReactiveAsyncCommand 为您做的一件事就是将结果返回给 UI 线程,因此您可以执行以下操作:

var cmd = new ReactiveAsyncCommand();
cmd.RegisterAsyncFunc(() => getAllTheItems())
   .Subscribe(theItems => theItems.ForEach(item => collection.Add(item)));

Subscribe保证在 UI 线程上(如果不是,那是一个错误)

于 2012-09-15T05:57:27.277 回答