I'm developing my first app for Windows Phone 7.1 using Reactive UI, and I'm facing difficulties working with ReactiveCollection class.
My app is roughly about accessing the WP7 SQL CE engine (LINQ to SQL). I would like to perform data operations in background, using ReactiveAsyncCommand. Data from database should "automagically" appear in UI, therefore I decided to use ReactiveCollection as a proxy between database and UI.
Here's my model, so you could have a better idea:
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;
}
}
}
In my view model I've tried using 2 different variants:
- Create a derived reactive collection and bind UI to it (With ReactiveCollection.CreateDerivedCollection() method. It's derived from the EncounteredModel.FactsCollection, for example.
- Use
ObservableAsPropertyHelper<IEnumerable<Fact>>
, then subscribe to Model's ReactiveCollectionChanged
IObservable to populate the OAPH.
Both variants, unfortunately, give me "Invalid cross-thread access." Stack trace is generally the same for both variants, here's one for the variant 1 (shortened to the significant part):
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)
When I change to ReactiveCommand (not async one), everything's fine. Any ideas how to overcome this? Much thanks in advance.