VM role in MVVM - should it handle everything and why? - mvvm

Where exactly is the limit to adopt VM so it can suite better a particular View? Example:
There should be a command in UI (ex button) that should allow adding new item. Additional requirement can be that new item should be selected, ensured that its visible on control (lets say TreeView control), and to begin edit on the newly added item (in order to change predefined value that was set in VM). Lets assume that control doesn't have automatic mechanism to achieve this, so we need to do it manually. So the execution flow looks like this:
invoke add command on VM - done is View's xaml.
set SelectedItem to new item (usually we bind control's SelectedItem property to VM's CurrentItem property, and then just assign new item to CurrentItem.
ensure that new item is visible on control - this must be done in View's code behind.
Start editing - this must be done in View's code behind.
Now, since everywhere on net there are articles on using messages for almost everything, a question:
What do I break if I do it in the simple old fashion way? I use Click event instead of Command binding on adding new item, and in the method I do this:
// in View's Click event handler
ViewModel.AddCommand.Execute(null);
EnsureVisibleSelectedItem();
BeginEdit();
.. clean and clear! And what do I gain if I do it using messages:
// in ViewModel's AddCommand
AddNewItem();
SetCurrentItem();
SendMessageToEnsureVisibleSelectedItem();
SendMessageToBeginEditSelectedItem();
... where View has registered to receive these two messages.
Any light on this is greatly appreciated. To my opinion, UI can change, and VM should be able to adopt new UI without making changes to itself, so I dont quite understand current MVVM policy that is preached on internet.

I would say "make it simple".
What's really important in MVVM is:
what doesn't depend on the view should go in the ViewModel (your ViewModel must not be aware of the view in any way - not just by object reference)
everything else in the View and its code-behind.
Yes, in its code-behind. There's nothing wrong in writing code-behind if it is code that is related to the view, not logic. For instance, drag & drop management should be written in the code-behind.
To answer your question, you do not break anything in writing:
// in View's Click event handler
ViewModel.AddCommand.Execute(null);
EnsureVisibleSelectedItem();
BeginEdit();
Everything that is not related to the view is in the ViewModel, everything else in the View/code-behind. That's just fine.
No if I look at your second example:
// in ViewModel's AddCommand
AddNewItem();
SetCurrentItem();
SendMessageToEnsureVisibleSelectedItem();
SendMessageToBeginEditSelectedItem();
AddNewItem is OK (not related to the view), SetCurrentItem is OK (not related to the view), but what about SendMessageToEnsureVisibleSelectedItem and SendMessageToBeginEditSelectedItem?
EnsureVisible is typically useful for a treeview, but what if your view wasn't built with a treeview? What if the control would automatically make the new selected item visible? Of course you could ignore the message, but you would have written some useless code in ViewModel because you thought your view would need it for UI display.
You have typically written here some code in the ViewModel that is aware of how the View should be working. Yes, you have reduced the number of lines in the code-behind, but you definitely have broken the pattern.
Your "old fashion way" is actually a good way for your needs. Your ViewModel is not aware of the view, that's what's important.

Related

How to model a NavigationStack in SwiftUI under iOS16 of a wizard view sequence?

Scenario
I have a wizard that all work on the same data object which is passed from step to step.
Steps:
Start
Some input values
Finish (draft becomes a actual db entry)
Current solution
Currently I use the old but working NavigationLink(isActive: ...). Now, I try to port my app to the new SwiftUI alongside iOS 16. That means the "old" NavigationLink is outdated. I tried NavigationStack with or without a $path, etc. pp
What's my actual problem?
All examples or great answers on SO I found (also from Apple) are "too simple" - I guess. I do not have a list, my navigation is "next"-Button-based. My "Destination view" is not just a TextField and I do not have a strict navigation flow (in future, there will be optional steps in between) as in the WWDC22 sample.
A step (aka View) will be also used in another wizard, too. Is this a good idea?
What I think, I need
My "wizard container view" I call it "flow" which embeds all other steps has to have a NavigationStack($path) {} component.
I have to make the path isn e.g. an EnvironmentObject that I can easily access and modify it during my wizard run from each child view.
I need a mapping using .navigationDestination(for: WizardNavigation.self) { switch ... } to show the requested next step.
But, what do I miss?
It feels over complicated and, again, to strict in navigation. The parent has to know all possible navigation destinations?
Please tell me, that I miss a big point that simplifies my whole approach.

How to pass a View to my ViewModel so an I*Service can use that View to do something

https://github.com/brianchance/MvvmCross-UserInteraction is a very nice plugin for showing cross platform Alerts!
But for this question, can we assume it can not use a UIAlertView (or some other top level MessageBox type call on other platforms) but needs to show a Message within a given subsection of the screen (i.e. on IPhone you would need to supply a UIView to the plugin which it will use to show the message within).
So, how would you set this up so the ViewModel knows what View to use as its display container?
As a specific example, if I wanted an Error Service, as so -
public interface IErrorPFService
{
void Show();
void Hide();
void SetErrors(List<Error> errors);
}
and I create a platform specific implementation for it.
If I inject this into my ViewModel so it can control Error Show/Hide/Set how do I tell it the UIView (or equivalent) that I want my Errors to show within?
Can I just expose the IErrorPFService field as a public property and do -
MyViewModel.ErrorPFService = new ErrorPFService(View);
in my ViewDidLoad ...
Or is this coupled incorrectly vs Mvvm Practice?
I would expect the ViewModel to subscribe itself to the ErrorService.
When receiving a message it would expose it in a collection(?) and the View would bind to that collection.
This way the View is unknown to the service and the ViewModel has the chance to influence the View contrary to your solution.
It would help if you could give an example for the scenario you are describing.
Sometimes, the way you visually want to display something might not be the best way, so if it's possible for you, you might find a different and simpler way, which spares you from having to find a solution regarding what you are describing.
Generally, I always do the best I can to avoid the idea of having to actually pass a 'view' or an abstraction of it, from the view-model to view. Also, cross-platform wise, things can work very different in terms of UI interaction. You can find yourself in a situation when things are complicated just because UI works differently than what you expected.
But let's try find another perspective:
At any given point, the view knows what data \ feature it's displaying. So when you are calling from the view-model an user interaction action (by a service, property change, event, etc) the view should 'expect' it.
For example, the platform specific user interaction implementation is able to get the currently displayed top-view and interact it in a platform specific manner or based a relationship. In your example, the message-box can be displayed in a specific sub-view of the top level view.
In advanced scenarios, I guess you could try to create a cross-platform approach for this, but you should try to put in balance all the abstraction you want to create just for that. Think about doing this as a plan ... Z. If possible. Again, giving an example might help.

How to communicate from ViewModel to View

I have a property on my ViewModel called LostFocus, and I want the View to know when this changes so that it can act on this info if it pleases (i.e. maybe the designer of the view might make it blur if LostFocus is set to true, or maybe they won't do anything).
I'm using Caliburn.Micro, so if it has any features I should be aware of here please do tell. Otherwise, how would you go about doing this in an MVVM fashion?
This can be accomplished with ordinary data binding as I understand it. Since you're using Caliburn.Micro, the designer can use conventions to do the binding. For example, if there were a check box control on the view that was to be checked when LostFocus is set to true, the designer would just have to ensure that the Name property of the check box was set to LostFocus and then Caliburn would set up the binding automatically.
Also, on your View Model, make sure you raise the property changed notification event when you change the value of LostFocus.
You could also, rather than using a LostFocus property, create a LostFocus event on your view model. You could then raise this event whenever you feel it's appropriate and then, on the view, the designer could respond to that using an event trigger and trigger action. For example, on one of my projects, I set up an event trigger to respond to the view model's Activated event and then I wrote a custom trigger action to play a storyboard that was responsible for doing the view's intro animation. This approach isn't restricted to Caliburn.Micro, but I did use it on a Caliburn.Micro project, so it definitely works.
I ended up learning about the BindingConverter and used that to convert a boolean property of false to null and true to a BlurEffect.

Best way to update view from command or filedialog in an eclipse rcp application

In my application I have a menu which open a SelectionDialog, this dialog is used to choose an object.
When this object is selected I have to display it in the view.
What is the best way to update my view?
Currently, I call myview.update(object) after the dialog is closed (in the handler of the menu). But I think this solution is not well design.
I have read about update my model and notify my view but my model does not change (no data are changed, I only display different Data ).
Does anyone has some ideas for a well design solution ?
Define model listener ( dataPopulated(Event e))
Make your view implement model listener and register it with the Model.
Define a Model class that can contain the objects that you want to populate in the view
When Model.setInput(Object input) is invoked fire dataPopulated() event on all registered model listeners.
Above steps works properly when you have view activated. You need to consider cases like when if view is deactivated or not visible ( make sure you refresh view is visible else you will have unnecessary overhead of refreshing view though it is notvisible)
Try adding a selection listener in the view and register this selection in the dialog.
In the listener action, add the code to show the selected object.

MVVM: Does the ViewModel format the data it gets from the model?

I'm a little confused about MVVM.
I understand the concept and can see the advantages. My problem is: does the ViewModel pass data directly from the model.
For example, let's say I have a "User" model with a findByName() method. The ViewModel would call this in order to pass
the relevant user details to the view.
The model would likely retrun a set of "User" objects each which has properties such as name, email address etc and may also have methods.
My question is, should the ViewModel return the set of User objects to the view, or return a restructured version of this which
contains only what the view needs?
As I understand it, the "User" object in this case is part of the model layer and in MVVM the View should be dependant only on the ViewModel.
My issue with this is the ammount of seemingly redundant binding logic required in the ViewModel that would be created to restructure the output.
Passing the set of User objects directly to the View (via the ViewModel) would be far simpler.
There's a little bit of redundancy, sure. However, if you implement MVVM by presenting the objects, you get to
format the model information for the view without polluting the model with presentation logic
notify the view when anything changes
use WPF's validation (if you're using WPF)
run acceptance tests from the VM level rather than the GUI if you want to
abstract your presentation away from any changes to the model.
That last one's important. Mostly presentation bindings nowadays are dynamic and fail silently - web pages, WPF, you name it. That means that if someone decides to rename something on the model, it will suddenly break in your GUI and you won't know.
By putting a VM between your Model and View you buffer yourself from changes like this.
If you want to go ahead and get something working with the Users as they are, I say go for it - it'll help you get fast feedback on your GUI. However, the first time those User objects don't do exactly what the View needs, or you need to notify the View of a change, or you find yourself polluting the model, or something in the binding breaks, maybe that's a good time to move to MVVM.
Doesn't that just move the break to the ViewModels which are using the model? You'd still need to go through and update all of those.
If I renamed something (e.g. changed "surname" to "lastname") I'd expect things to break. I don't see how adding the binding in the VM layer fixes that.