Question

I have a specific data set that requires storing data that is both grouped and ordered. Each row then needs to be able to recalculate it's sums whenever any individual item changes.

This is the basic look of the end result:

enter image description here

The object structure is as such:

public class MyObject : INotifyPropertyChanged
{
  public ObservableCollection<MySubObject> Objects { get; set; }
  public Decimal TotalOfAll { get; set; }

  /* Ommited INPC and other properties for brevity */
}

public class MySubObject : INotifyPropertyChanged
{
  public Decimal Value { get; set; }
  public String RowType { get; set; }

  /* Ommited INPC and other properties for brevity */
}

The view needs to bind to MyObject, then group the Objects property by it's Type property.

Now, I've already accomplished this without using reactive extensions, but it feels hackish...I would like to accomplish this by converting the Objects property of MyObject to an observable which should, in theory, allow me to update the sums whenever the Value property of MySubObject changes.

I already have the view side of things built, so that's not the issue...it's getting the RX part completed.

NOTE:

I can alternatively expose my data like this:

public class MyObject : INotifyPropertyChanged
{
  public ObservableCollection<MyRowObject> Objects { get; set; }
  public Decimal TotalOfAll { get; set; }

  /* Ommited INPC and other properties for brevity */
}

public class MyRowObject : INotifyPropertyChanged
{
  public ObservableCollection<MySubObject> Objects { get; set; }
  public String RowType { get; set; }
  public Decimal RowTotal { get; set; }

  /* Ommited INPC and other properties for brevity */
}

public class MySubObject : INotifyPropertyChanged
{
  public Decimal Value { get; set; }

  /* Ommited INPC and other properties for brevity */
}

This would take care of the grouping issue, but I still cannot get it to work

Was it helpful?

Solution

You can use ReactiveUI's reactive collection, which provides a number of observables including one for when the collection changes (Changed), and one for when the items in the collection change (ItemChanged). This can be combined with ObservableAsPropertyHelper for the dependent properties.

The totalOfAll dependent property is quite straightforward. The other dependent property - groupedObjects - is a bit more complex. I'm not sure if I've understood your grouping requirements exactly. Hopefully the code below will be a starting point - it will project the collection of subobjects into an IEnumerable of anonymous objects, each containing a total, a row header, and the items. You should be able to bind to this in your view

public class MyObject : ReactiveObject
{
    public ReactiveCollection<MySubObject> Objects { get; set; }

    private ObservableAsPropertyHelper<IEnumerable<object>> groupedObjectsHelper;
    public IEnumerable<object> GroupedObjects
    { 
        get {return groupedObjectsHelper.Value;}
    }

    private ObservableAsPropertyHelper<Decimal> totalOfAllHelper;
    public Decimal TotalOfAll 
    {
        get {return totalOfAllHelper.Value;}
    }

    public MyObject()
    {
         var whenObjectsChange=
           Observable.Merge(Objects.Changed.Select(_ => Unit.Default),
                            Objects.ItemChanged.Select(_ => Unit.Default));

         totalOfAllHelper=
           whenObjectsChange.Select(_=>Objects.Sum(o => o.Value))
                            .ToProperty(this, t => t.TotalOfAll);

         groupedObjectsHelper=
           whenObjectsChange.Select(_=>Objects
                              .GroupBy(o => o.RowType)
                              .Select(g => new {RowType=g.Key,
                                                RowTotal=g.Sum(o => o.Value),
                                                Objects=g}))
                            .ToProperty(this, t => t.GroupedObjects);

    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top