What are the major difference between bindable LINQ and continuous LINQ?
•Bindable LINQ: www.codeplex.com/bindablelinq
•Continuous LINQ: www.codeplex.com/cli
Indeed; the main issue with Continuous LINQ is the inability to use any collection that implements the generic IEnumerable and INotifyCollectionChanged. Bindable LINQ has no problem with using custom collections implementing the two interfaces.
Another thing to keep in mind, although BindableLinq requires the ".AsBindable()" call in the LINQ statement, CLINQ requires that you use ContinuousCollection<T> instead of ObservableCollection<T>. After looking at both briefly, I think I'm going to go with bindable LINQ.
Use bindable LINQ, as it implements IDisposable, and therefore you can control when a query gets disposed. When you dispose it, all the subscriptions to INotifyPropertyChanged will unsubscribe.
Continuous LINQ is supposed to solve this problem with weak events, but it doesn't work as far as I was able to test.
Hmm... this seems to be a problem with bindable LINQ (the second assert fails):
var _source = CreateSource_6People(); //(David, 27), (Mark, 15), (Steve, 30), (Jordan, 43), (Shiva, 30), (Erb, 43)
IBindable<int> bindable = _source.AsBindable().Sum(x => x.Age);
var agesSum = 27+15+30+43+30+43;
Assert.AreEqual(agesSum, bindable.Current); //PASSES
_source[0].Age += 1;
Assert.AreEqual(agesSum + 1, bindable.Current); //FAILS... DISAPPOINTING
May I draw your attention to another codeplex project? It's called Obtics and deals with the same issues (http://obtics.codeplex.com).
It addresses both the first the second and the additional problem and takes reactivity to a very deep level (has a demonstration with a LINQ based raytracer).
It claims full support for all LINQ statements an methods of the Enumerable class.
It uses yet another mechanism to create live queries:
var theResultSet = ExpressionObserver.Execute(
() => from item in theSource where item.Age > 25 select item
).Cascade();
Their are 2 problems both these packages try to solve: Lack of a CollectionChanged event and Dynamic result sets. There is one additional problem bindable solves, additional automatic event triggers.
The First Problem both packages aim to solve is this:
Objects returned by a LINQ query do not provide CollectionChanged events.
Continuous LINQ automatically does this to all queries, with no change:
from item in theSource select item ;
Bindable LINQ does this when you add .asBindable to your query Source Object:
from item in theSource.AsBindable() select item ;
The Second Problem both packages aim to solve is:
Result sets returned from a LINQ Query are static.
Normally when you do a LINQ Query your result set is unchanged until you do a new query. With these two packages, your result set is updated whenever the source is updated. (bad for performance, good for realtime updates)
Example
var theSource = new ContinuousCollection<Customer>();
var theResultSet = from item in theSource where item.Age > 25 select item;
//theResultSet.Count would equal 0.
Because your using Bindable or Continuous LINQ, you could modify theSource, and theResultSet would automatically include the new item.
theSource.Add(new Customer("Bob", "Barker" , 35, Gender.Male)); //Age == 35
//theResultSet.Count would now equal 1.
The Additional Problem Bindable LINQ offers: (Quoting directly from their own page)
contactsListBox.ItemsSource = from c in customers
where c.Name.StartsWith(textBox1.Text)
select c;
Bindable LINQ will detect that the query relies on the Text property of the TextBox object, textBox1. Since the TextBox is a WPF control, Bindable LINQ knows to subscribe to the TextChanged event on the control.
The end result is that as the user types, the items in the query are re-evaluated and the changes appear on screen. No additional code is needed to handle events.
I think Bindable LINQ and continuous LINQ are about the same: they provides observing for changes in LINQ computation. Implementation and API provided may some differ. It seems my ObservableComputations library covers functionality expected from Bindable LINQ and continuous LINQ and has no problems mentioned in https://stackoverflow.com/a/174924/2663791. That library works with INotifyPropertyChanged and INotifyCollectionChanged interfaces, that makes it possible to operate with ObservableCollection direcly. Using that library you can code like this:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using IBCode.ObservableComputations;
namespace ObservableComputationsExamples
{
public class Order : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int Num {get; set;}
private decimal _price;
public decimal Price
{
get => _price;
set
{
_price = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Price)));
}
}
public Order(int num, decimal price)
{
Num = num;
_price = price;
}
}
class Program
{
static void Main(string[] args)
{
ObservableCollection<Order> orders =
new ObservableCollection<Order>(new []
{
new Order(1, 15),
new Order(2, 15),
new Order(3, 25),
new Order(4, 27),
new Order(5, 30),
new Order(6, 75),
new Order(7, 80),
});
//********************************************
// We start using ObservableComputations here!
Filtering<Order> expensiveOrders = orders.Filtering(o => o.Price > 25);
checkFiltering(orders, expensiveOrders); // Prints "True"
expensiveOrders.CollectionChanged += (sender, eventArgs) =>
{
// see the changes (add, remove, replace, move, reset) here
};
// Start the changing...
orders.Add(new Order(8, 30));
orders.Add(new Order(9, 10));
orders[0].Price = 60;
orders[4].Price = 10;
orders.Move(5, 1);
orders[1] = new Order(10, 17);
checkFiltering(orders, expensiveOrders); // Prints "True"
Console.ReadLine();
}
static void checkFiltering(
ObservableCollection<Order> orders,
Filtering<Order> expensiveOrders)
{
Console.WriteLine(expensiveOrders.SequenceEqual(
orders.Where(o => o.Price > 25)));
}
}
}
Please, add ObservableComputations library to the list in the question (after Obtics).