Zipping Rx IObservable with infinite number set - linq

I have a IObservable [named rows in the sample below] from Reactive extensions framework and I want to add index numbers to each object it observes.
I've tried to implement this using Zip function:
rows.Zip(Enumerable.Range(1, int.MaxValue), (row, index) =>
new { Row = row, Index = index })
.Subscribe(a => ProcessRow(a.Row, a.Index), () => Completed());
.. but unfortunately this throws
ArgumentOutOfRangeException:
Specified argument was out of the range of valid values.
Parameter name: disposables
Am I understanding the Zip function wrong or is there a problem with my code?
The Range part of the code doesn't seem to be the problem and the IObservable isn't yet receiving any events.

.Select has an overload to include the index:
rows.Select((row, index) => new { row, index });

Apparently, Zip extension methods converts the original custom IObservable to an anonymous observable and Subscribing to it creates an System.Collections.Generic.AnonymousObserver, which doesn't implement IDisposable.
Thus, you cannot implement the Subscribe method the normal way (atleast the way I've seen it used), which is
public IDisposable Subscribe(IObserver<T> observer) {
// ..add to observer list..
return observer as IDisposable
}
More likely the correct answer would be:
return Disposable.Create(() => Observers.Remove(observer));
You should though note that the collction will probably be modified durin Completed-method, so create a copy of the list before processing them:
public void Completed()
{
foreach (var observer in Observers.ToList())
{
observer.OnCompleted();
}
}

I am not sure what your problem is, does this work for you (and what's missing here that you are doing?):
static void Main(string[] args)
{
var rows = new List<int> { 4,5,1,2,5 }.ToObservable();
rows.Zip(Enumerable.Range(1, int.MaxValue), (row, index) =>
new { Row = row, Index = index })
.Subscribe(a => ProcessRow(a.Row, a.Index), () => Completed());
Console.ReadLine();
}
static void ProcessRow(int row, int index) {
Console.WriteLine("Row {0}, Index {1}", row, index);
}
static void Completed() {
}

Related

How to subscribe new value in Akavache?

I'm using Akavache's GetAndFetchLatest method and I have created dependency services to communicate with Akavache's method. I'm calling akavache from service layer successfully when i directly reference. For subscribing
MyMod result = null;
var cache = BlobCache.LocalMachine;
var cachedPostsPromise = cache.GetAndFetchLatest(
"mykey",
() => GetInfo(),
offset =>
{
//some condition
});
cachedPostsPromise.Subscribe(subscribedPosts => {
Device.BeginInvokeOnMainThread(() =>
{
//do sothing.
});
});
result = await cachedPostsPromise.FirstOrDefaultAsync();
return result;
It works.But how an I call subscribe on service layer with interface/dependency service?
I think you are new to reactive programming. Understanding the basic principles helps when using Akavache. Maybe this intro helps.
To answer your question, place code like this in your "repository" class:
public override IObservable<MyClass> Get(string key)
{
var cachedObservable = blobCache.GetAndFetchLatest<MyClass>(key,
() => GetFromServerAsync(key));
return cachedObservable ;
}
And in the caller:
private void getNewData()
{
var myClassObservable = myRepository.Get("the key");
myClassObservable.Subscribe(handleNewMyClass);
}
private void handleNewMyClass(MyClass newClass)
{
//handle the new class
}
Note that handleNewMyClass() is called twice:
first with the MyClass from cache
then with the MyClass that was fetched (from the server)
Using this approach you can simply place the repository class in your IoC Container.
Please find the the sample code :
var result = BlobCache.LocalMachine;
var cachedPostsPromise = cache.GetAndFetchLatest(
"mykey",
() => ViewModelLocator.GetInstance<IYourServiceName>().MethodName(),
offset =>
{
//some condition
});
cachedPostsPromise.Subscribe(subscribedPosts => {
Device.BeginInvokeOnMainThread(() =>
{
//Your piece of code
});
});
result = await cachedPostsPromise.FirstOrDefaultAsync();
return result;
Please note the there any anything inside subscribed will be called twice : first set of data will be cache and second set will be freshly fetched from server.You have to manage according.

How to get selected items from a SWT Table using RxJava?

I have a table and a button and I want to emit an event ItemsSelected with the selected items of the table when the button is clicked.
The button should not know the table and it should remain only as a stream of clicks.
So this solution is discarded:
final ETable table = ...
PublishSubject<ItemSelected> selected = PublishSubject.create();
button.addSelectionListener(new SelectionListener(){
#Override
public void widgetSelected(SelectionEvent e) {
for (TableItem item : table.getSelection()) {
selected.onNext(new ItemSelected(item));
}
}
});
I would prefer a way to compose the click stream of the button with the item selection stream of the table in order to keep loose coupling between this two elements.
Because the table allows multiple selection I must first scan the items selected in order to emit an event with all the items. Something like:
public static class ItemsSelected<T> {
final List<T> items = new ArrayList<T>();
}
public abstract static class ItemSelection<T> {
public abstract void apply(ItemsSelected<T> selection);
}
public static class ItemUnselected<T> extends ItemSelection<T> {
final T item;
public ItemUnselected(T item) {
this.item = item;
}
public void apply(ItemsSelected<T> selection) {
selection.items.remove(item);
}
}
public static class ItemSelected<T> extends ItemSelection<T> {
final T item;
public ItemSelected(T item) {
this.item = item;
}
public void apply(ItemsSelected<T> selection) {
selection.items.add(item);
}
}
public static class ObservableTable<T> extends Table {
private PublishSubject<ItemSelection<T>> clicks = PublishSubject.create();
public Observable<ItemsSelected<T>> selection = clicks.scan(new ItemsSelected<T>(),
new Func2<ItemsSelected<T>, ItemSelection<T>, ItemsSelected<T>>() {
#Override
public ItemsSelected<T> call(ItemsSelected<T> t1, ItemSelection<T> t2) {
// breaking events immutability
t2.apply(t1);
return t1;
}
});
public ObservableTable(Composite parent, int style) {
super(parent, style);
this.addSelectionListener(new SelectionListener() {
#SuppressWarnings("unchecked")
#Override
public void widgetSelected(SelectionEvent e) {
if (((TableItem) e.item).getChecked())
clicks.onNext(new ItemSelected<T>((T) e.item.getData()));
else
clicks.onNext(new ItemUnselected<T>((T) e.item.getData()));
}
#Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
}
}
Then, I must combine the table.selection stream with the button.clicks stream in a selectionForAction stream. The idea is that when a ButtonClick is emitted, an SelectionForAction will be emitted if and only if an ItemSelected was previously emitted.
-------S1--U1-----S2---S3--------- table.clicks
(scan)
-------(1)--()---(2)---(2,3)------ table.selection
----O----------O-------------O---- button.clicks
(?)
-----------------------------(2,3) selectionForAction
So, wich operation should I use?
Zip: It doesn't work because if I click the button and later select an item, it should not do nothing, but with zip it will emit an event.
Join: I end up with a "solution" using join but it doesn't seem to be a good one. Somethinkg like:
table.selection.join(button.clicks, new Func1<ItemsSelected,Observable<Long>>() {
#Override
public Observable<Long> call(ItemsSelected t) {
// it doesn't seem a good idea
return Observable.timer(1, TimeUnit.DAYS);
}
}, new Func1<ClickEvent, Observable<Long>>() {
#Override
public Observable<Long> call(ClickEvent t) {
// this makes the ClickEvent be dropped if there is no previous ItemsSelected event emitted
return Observable.timer(1, TimeUnit.MILLISECONDS);
}
}, new Func2<ItemsSelected, ClickEvent, SelectionForAction>() {
#Override
public SelectionForActioncall(ItemsSelected t1, ClickEvent t2) {
return new SelectionForAction(t1.items);
}
});
Any idea?
I've found the operator that I needed to achieve the join behaviour with a very large time unit (DAYS in the example) and a very small one (MILLISECONDS).
With a variant of sample that takes another Observable as the sampler I could emit an event A only after an event of B would be emitted.
In my example the click acts as the sampler and the stream selection emits the events that I'm interested in. (This also requires to ignore the last event that is being emitted when the stream completes).
Another possible solution will be use the buffer(boundary):
The clicks stream would act as the boundary and I could avoid the scan operator because the list of items selected is created by the buffer operator. However with this solution I would not be considering unselection.
So, with sample I've achieved my original goal, however, I'm not happy with the way I handle items unselection and the final list of items selected.
In this case I need to maintain the state of the items selected in order to perform some operation on all of them when a ClickEvent occurs.
I could subscribe to the items selection/unselection and maintain a List of the items selected but then I'll have lost the possibility of compose the clicks observable with the selection observable.
With scan I maintain state and also keep the composability of observables, but representing the list of current selection as an event seems a little forced, in fact this represents a new issue: if I select x items and then click the button, an event with the selection is being emitted as expected, but if neither the items are unselected nor a new one is selected and then click again the button, nothing happens. So, it seems that selection doesn't fit as an event.

WhenAny / ObservableForProperty how to access previous and new value?

Simple case:
public class Foo : ReactiveObject
{
public Foo()
{
this.ObservableForProperty(t => t.Bar, t => t).Subscribe(t =>
{
//Logic using previous and new value for Bar
}
}
private int _bar;
public int Bar
{
get { return _bar; }
set { this.RaiseAndSetIfChanged(ref _bar, value); }
}
}
In the ObservableForProperty subscription, only the new value of Bar is accessible (via t). We can call ObservableForProperty with true for the "beforeChange" parameter, and instead only have the previous value and not the new.
I know I can just plug my code logic in the property setter, but I'd like to keep the ObservableForProperty behavior (filter the first setter and when the value does not change). The property is also used in a XAML binding and require the propertyChanged trigger.
Anything I missed? How can I do that easily? Thanks
How about something like this:
public Foo()
{
this.WhenAnyValue(t => t.Bar)
.Buffer(2, 1)
.Select(buf => new { Previous = buf[0], Current = buf[1] })
.Subscribe(t => { //Logic using previous and new value for Bar });
}
Note that this will not trigger the subscription logic the first time you alter the Bar. In order to get that functionality, add .StartWith(this.Bar) before buffering.
This uses Buffer operator in overlapping mode (skip < count).

ReactiveCollection and invalid cross-thread access

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 ReactiveCollection Changed 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.
ReactiveCollection doesn't proxy everything to the UI thread, if you add items to it from a worker thread, you will signal the UI on that same thread and get the crash.
However, one thing that ReactiveAsyncCommand does for you is give you back the results back on the UI thread, so you can do something like this:
var cmd = new ReactiveAsyncCommand();
cmd.RegisterAsyncFunc(() => getAllTheItems())
.Subscribe(theItems => theItems.ForEach(item => collection.Add(item)));
The Subscribe is guaranteed to be on the UI thread (if it isn't, that's a bug)

Errors using a LINQ query in a Silverlight application

I am trying to consume the WCF services using Silverlight application in Sharepoint.
It's going to display all the data from a list in a grid. Somehow it is throwing a error.
Cannot convert lambda expression to type 'system.Delegate' because it is not a delegate type.
using the generic type 'system.collections.generic.ienumerable' requires 1 type arguments
SLprojectsCRUD2010WCF.sharepointservice.list1item' is a type but is used like a variable.
How can this be solved?
private SharePointService.SkinnyBlondeDataContext _context;
public MainPage()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(LayoutRoot_Loaded);
}
private void ShowProjects()
{
// Declare the LINQ query
var projectsQuery = (from p in _context.Tasks
select p) as DataServiceQuery<SharePointService.TasksItem>;
// Execute the LINQ query
projectsQuery.BeginExecute((IAsyncResult asyncResult) => Dispatcher.BeginInvoke(() =>
{ // Runs in the UI thread
// EndExecute returns
IEnumerable < TasksItem > this.dataGridProjects.ItemsSource = projectsQuery.EndExecute(asyncResult).ToList();
}), projectsQuery);
}
private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
// Get the context
_context = new SharePointService.SkinnyBlondeDataContext(
new Uri("http://vanir0269/_vti_bin/listdata.svc", UriKind.Absolute));
ShowProjects();
}
Until your source code is formatted properly it'll be a pain to see what the LINQ problem is, but the lambda expression problem is easy: Dispatcher.BeginInvoke takes a Delegate, and lambda expressions can only be converted into specific delegate types. This is easy to fix:
projectsQuery.BeginExecute((IAsyncResult asyncResult) => {
Action action = () => {
// Code in here
};
Dispatcher.BeginInvoke(action, null);
});

Resources