In applications, a situation often arises when it is necessary to compute some value on the basis of the source data. Let me give you a simple example, in real life everything can be more complicated (bindable Linq is more applicable to more complicated cases). For example, you need to compute the final price based on the original price and discounts for each product in the order. In case the order items (add, remove) or the discount changes, we must also update the final price. Without using bindable Linq, there are 2 options to achieve this:
1) Call the method of recalculating the total price each time the order items (add, remove) or discount changes.
2) Call the method of recalculating the total price by timer (every 5 seconds)
Each of these methods has disadvantages.
The first method has the following drawback: since we must call the method of recalculating the total price in many places in the code, we may forget to call the method of recalculating the total price somewhere.
The second method has the following disadvantages:
1) delay in refreshing the total price in UI
2) the method of recalculating the final price will be called in vain when the composition of the order and the discount have not changed, which can adversely affect performance
Both methods have the following drawback: the method of recalculating the final price each time brings the entire calculation anew (enumerates all order items), instead of taking into account a separate change in one item. This can adversely affect performance.
With bindable Linq, we only need
1) determine how the final price is calculated
2) use INotifyPropertyChanged and INotifyCollectionChanged interfaces.
I want to introduce you to my library implementing this approach: ObservableComputations. With this library, we can code like this:
public class Order : INotifyPropertyChanged
{
public ObservableCollection<OrderItem> Items {get; set;}
private int _discount;
public int Discount
{
get => _discount;
set
{
_discount = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Discount)));
}
}
private Computing<decimal> _totalPrice;
public Computing<decimal> TotalPrice => _totalPrice = _totalPrice ??
Items.Selecting(i => i.Price * i.Quantity).Summarizing()
.Using(totalOriginalPrice =>
totalOriginalPrice.Value
- totalOriginalPrice.Value * Discount / 100);
public event PropertyChangedEventHandler PropertyChanged;
}
public class OrderItem : INotifyPropertyChanged
{
private decimal _price;
public decimal Price
{
get => _price;
set
{
_price = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Price)));
}
}
private int _quantity;
public int Quantity
{
get => _quantity;
set
{
_price = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Quantity)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Actual value we need is stored in TotalPrice.Value. TotalPrice returns an instance of INotifyPropertyChanged and notifies you when Value property changes, so you can bind this property to the control of the WPF, Xamarin (I believe this will be true for Blazor too). Value property changes when Items collection or Discount, Quantity, Price properties changes.
Here you can see a discussion of other similar libraries.