Tracking of collection changes with Rx in MVVM - c#

I have a cross-platform project written using MVVM-pattern (no specific frameworks used, just self-written implementation). Project has several independent modules each of which has several pages.
Each of pages has ViewModel and some sort of manager who's responsible for data-oriented logic (get, save, delete, transform etc.). So the data-flow looks about this:
VM -> Manager -> Service -> Manager -> VM
When VM is loaded it's asking manager for data. Manager perform service call, get data, construct collection of models from DTOs, return this collection to ViewModel which converts collection of models to collection of ViewModels
to be rendered in the list.
Now I'm looking for a way to implement this kind of logic using Rx. Most of pages have one main list to be edited (items inserted, deleted, modified) and several support collections (providers for some combo-box to choose value from).
Support collections can be easily retrieved via standard async/await calls or via converting tasks to Rx - they are no problem. But the modifiable list is.
I just cannot figure out the way to track changes in this list for the entire life of the page without breaking Rx logic.
I have options to subscribe to:
IEnumerable<Model>
Task<IEnumerable<Model>>
IObservable<IEnumerable<Model>>
but I suppose I have to subscribe for IObservable<Model> because I need a way to track individual changes.
And I need a way to modify this collection from other methods like Add, Delete or Edit.
So should I create IObservable via Observable.Create (or other method) and store IObserver somewhere inside Manager to call OnNext or OnError in other methods? But it doesn't looks like an Rx-way-to-do.
Do you have any suggestions about my problem? Any advise appreciated. Thanks.
PS: you may say Rx isn't the best way to solve my problem with tracking modifiable list because it's not endless stream of events and I have to push modifications by myself but Rx has very convenient way of filtering data and handling errors so I'm really looking forward to implement it in the application.

Look at ReactiveList<T> - it's part of ReactiveUI framework which we've used to great effect with MVVM / WPF UIs.

ReactiveList works, although it doesn't have any single Rx stream exposed which provides all modification events.
See this related question, which answer is to use an IObservable<IObservable<Model>>, with each inner observable representing one item from your list, along with its modifications (and deletion - when it completes).

Related

C# MVVM Model Graph Message Mediator or INotifyPropertyChanged?

I am developing a C# MVVM WPF app and have problems to decide whether I should use the message mediator pattern or simple INotifyPropertyChanged for my UI 'live' Model change notifications. The problem in particular is that my model represents a graph with lots of 'live' objects that all have properties where different viewmodels will be interested in the changes at some point. I have about 3-5 viewmodels active that need notification of model changes. Some changes might be nested deep inside the models 'grandchildren'.
I tried to compare both messaging techniques, mediator pattern and INotifyPropertyChanged, and think that the mediator is better suited for change notifications between different modules/systems. My viewmodels definitely need the initial values of the model upon initialization and then change notifications afterwards. INotifyPropertyChanged seems to be the optimal choice in my case, but I am a bit skeptic, because I think lots of nameof(e.PropertyName) switch cases are not very elegant. Are there better alternatives for this problem?
As is typical for such cases, you could have both ways. You will obviously not be able to avoid using INotifyPropertyChanged because this is the WPF way of handling MVVM-based Data Binding, so all your view-models will be at least basic implementations of this interface.
I suspect that you might simply need both. I would not suggest using the INotifyPropertyChanged-based pattern inside your model. The reason this interface was created was to base the observer pattern on actual property names as strings. This was pretty much a "one-way street", as XAML, the typical "design" language supporting WPF, is parsed in a "stringly" manner, leaving few efficient alternatives. In my humble opinion, there is almost no reason that you would want to force notifications throughout your model to be as weakly-typed (stringly-typed, in fact) as this scenario, so I would suggest avoiding INotifyPropertyChanged if you have a relatively voluminous Domain Model.
Messaging would probably be the way to go, maintaining strong-typing with message type registrations and whatnot, unless you would like to consider other alternatives, such as simple C# events, or even combine both. While at it, try to stick and adhere to hierarchy and encapsulation as strongly as possible but also as weakly as practical*.
(*I mean, if some of your Domain objects reach multiple nesting levels, then, occasionally, it may be more practical to bypass hierarchy and let, for example, grand-grandchildren send messages of their own, instead of notifying their parents' parents through events, and letting these parents' parents then send the corresponding notification messages. In typical OOP programming, compromises are constantly weighted against practicality and time availability).

Is grouping View Model properties into different categories a good practice?

I'm working on a WPF project using the MVVM pattern and I was wondering if I can improve the internal structure of my ViewModel by abstracting its exposed properties into separate classes.
It's common practice for VMs to contain lots of properties laying around in the same class: Some are used to retrieved user inputs, some are used to expose commands, others to expose the models, and probably some other properties for the view model's own business logic. Not to mention that these properties often have set and get bodies that adds some bulk to the package. This can quickly become messy inside a VM class and finding one's way there can become challenging.
As a way to solve this issue, I am exploring with my team the idea of grouping properties inside my VM into different categories. As a first approach, I chose to group them this way:
ViewData, UserInputs and Commands, each one represented by its own class. Then I referenced them as properties inside my VM class.
My intention is that these classes will only act as placeholders to free up the bloat in my VM and keep it clean and focused only on interaction logic for handling user events.
It's a simple refactoring, but I get the following pros:
Cleaner and readable VM.
Easier binding from the XAML because you know what the entry point is/should be.
Let me elaborate on the latter one: If I want to bind a text box to a property of my VM, I know the binding expression should start with Userinput.MyVMProperty. If I need to show a value from my VM, I know my binding's entry point is going to be ViewData.MyOtherVMProperty. Binding intellisense will also become better because when you know your entry point, the
suggestion list would be smaller and more focused. This also works the other way around: when reading through your XAML controls, any binding that starts with UserInput necessarily means it's a a control that should send data back to the VM.
The only cons I can find is that this will require creating extra classes for each VM, but I believe it's a fair price to pay for the benefits you get.
Take note that the grouping I suggested may not be the best, but I don't mind any other grouping as long as it solves the problem with bulky VMs.
So, has any one ever tried a similar pattern? Do you think this is a good idea/practice? What other good practices I can use to improve my VMs?
Bonus question: One developer in my team who seemed to agree with this idea, suggested to go the extra mile and consider the grouped classes as VM dependencies and that they need to be injected inside the VM. What do you think about this?
So for every ViewModel you need to create own inner classes for every group. You cannot use Interfaces because ViewModels have different properties and commands
Then did you considered that every "groupclass" must to "know" about other groups for ViewModel will work properly.
In my opinion Class should be solid logical structure with minimal outside dependency.
Based on the pros you trying to achieve I can suggest another approach without changing structure of the ViewModel classes
Readability can be achieved partly by #regions.
Or use Partial class for separating different groups in the different files,
while keeping them inside one logical structure
Intellisense can be improved by naming conveniences - using prefix based on group property belong to. For example UserInputMyName, ViewDataFullName or CommandDelete

Should items flowing in a TPL Dataflow network be DTO or POCO?

(Now that I have your attention with acronyms ...)
Maybe a better way to ask the question is: When should you use DTOs and when POCOs in a TPL Dataflow network? (Because the better choice may depend on circumstances).
I've done it both ways and I'm unsure of when to use one vs. the other. Should the processing logic be in the block (i.e., the lambda you pass to the standard blocks) or should it be encapsulated, as per usual, in the object?
(As a reminder, what DTOs and POCOs are is discussed in this POCO vs DTO question.)
I lean about 70% towards DTOs flowing in the network because:
My mental model, when designing/coding a dataflow network, is concentrating on a multi-stage transformation pipeline - data gets transformed and transformed again and then again. The focus is on the transformations, not on the "behavior" of each kind of data item. I want to see the transforms laid out as a bunch of (relatively) small functions (lambdas) that I can browse together.
The items in the flow aren't usually instances of model classes for the application, they're usually just instances that are created within the flow and destroyed by the end of the flow. (Sometimes they live only long enough to pass from one block to the other.)
On the other hand:
You could sometimes think of the data items as undergoing successive transforms, which would weigh towards the data classes encapsulating behavior.
If you do encapsulate behavior in the data classes then creating the dataflow blocks and hooking them up becomes boilerplate (since there is no data specific work done in the block's lambdas) and thus you can create rather generic builders that easily describe building any network.
(The only thing I'm relatively sure of is that the styles shouldn't be mixed in one network.)
But I don't have enough varied experience to be able to formulate any guidelines to suggest how to choose. I'm looking for such guidelines, or pro/con arguments to consider.
It depends on what kind of processing you are performing, and I don't think TDF has any effects on this decision.
If the operation you're performing is truly a "method" of the item (like Eat is for a Hamster) then have the logic on the item itself. If on the other hand, there's no real relation between the item and the process (like logging for example) and the item simply "passes through" a block then have the logic on the block's method.
What should be the base class of Petri Net Tokens?
What should be the base class of Object Nodes in UML Activity Diagrams?
Any class will do
Although your question is lengthy, for me it falls into the same question/answer category

Why does ObservableCollection not support bulk changes?

What are the potential problems caused by an ObservableCollection supporting operations like AddRange or RemoveRange? There must be a reason why Microsoft didn't provide them, now that ObservableCollection is so frequently used with WPF.
You could implement your own collection that supports bulk operations and implements INotifyCollectionChanged. What happens if I bind such a control to an ItemsControl?
Does anyone know of ItemsControls that don't support bulk changes?
I don't think it's that there are any potential downsides or problems, it's just that it isn't there. In fact, you will find that most types in 'System.Collections.Generic' don't supply 'AddRange' functionality either.
Meanwhile, lots of people have created their own versions of 'ObservableCollection' to provide the functionality that you want. INotifyCollectionChanged contains enough information for its handlers to make note of when a range of items have been affected probably for this reason.
Last but not least, if you bind a collection that has these 'Range' type operations you will find that they will work with your UI as you expect
There are numerous extensions to ObservableCollection that can be found on the internet that add the concept of add / remove range, or allow you to defer updates and fire them manually. For example see this Stack Overflow question:
ObservableCollection Doesn't support AddRange method, so I get notified for each item added, besides what about INotifyCollectionChanging?
You can also implement a bulk add that fires a reset event, which will cause the UI to re-render all of the items in the collection:
http://peteohanlon.wordpress.com/2008/10/22/bulk-loading-in-observablecollection/
These allow you to more efficiently manage the UI updates. How an ItemsControl handles a collection changed event which details a list of changed items is up to the WPF framework itself. I am assuming it handles this intelligently!
My advice to you is, if performance is critical to you and you have collections with numerous items being updated and are experiencing performance problem, then subclass ObservableCollection to manage collection changed notification in a manner that best fits your application's needs.
NotifyCollectionChangedEventArgs includes index information. Removing items causes indexes to reshuffle, as does inserting items. Hence, whilst not entirely impossible, it would be rather difficult and probably inefficient to provide the ability to work with ranges.
There must be a reason why Microsoft didn't provide them
They do not provide every possible piece of functionality, it's (also) a cost vs. demand thing.
You could implement your own collection that supports bulk operations and implements INotifyCollectionChanged.
Yes. And when you do, you'll find that the collection will have to make choices about how/when to propagate those changes. I never tried but I imagine there are some trade-offs that the View or ViewModel can make better decisions about than a reusable collection.

Notify Gui that data class has changed

In C#:
I have a data class that is shared amongst several gui classes. I would like all of the gui classes that use it to be notified when some of the properties change, so they can keep the GUI up to date.
In a couple of the properties I have added delegates that the GUI classes can listen to for updates. This seems to work ok.
The problem I have is that more and more of the properties will require GUI notification. When that happens I will have to add more delegates. It also seems that this is adding an extra responsibility to the data class that it has to manage.
Is there some common pattern that I can use to monitor this class to extract this notification responsibility from the data class?
The common way of doing this is for the data class to implement INotifyPropertyChanged.
EDIT: If you have a lot of properties, this can lead to very repetitive code in the data class, and if you are binding to a UI, it might be best to use an AOP approach and intercept calls to the properties that you want to notify on. Most IoC containers have support for this sort of thing.
The pattern is called Observer. In .Net, events are one implementation of that pattern.
For the specific case of observing individual properties, the INotifyPropertyChanged interface should be used (as #Lee describes).
You don't say what GUI framework (WinForms, WPF) you are using, but there is the INotifyPropertyChanged interface. There is an How to guide on MSDN too.
You can just use the built-in System.EventHandler. That is a pretty standard pattern. You still need to define an event for each property that you want to monitor, but you don't need a separate delegate.
In Windows Forms there are several ways to notify GUI when some properties are chaged using Data Binding.
There are several types of Data binding in Windows Forms.
For simple data binding (data source with one object boud to one control) you can use INotifyPropertyChanged, or you can add events in this format: PropertyNameChanged for every property that you want update in GUI. And you should set Binding.ControlUpdateMode property to OnPropertyChanged.
For complex data binding (data source with many objects bound to control that can display many objects) you should use all from (1) and you should use BindingSource or BindingList or manually implement IBindingList;
For more information you should see this great books:
Windows Forms 2.0 Programming by Chris Sells
Data Binding with Windows Forms 2.0: Programming Smart Client Data Applications with .NET by Brian Noyes

Categories

Resources