I know there's a lot of questions on the topic and I understand how to do it but I need some help on the design of my architecture. I'm using the Simple MVVM Toolkit.
Architecture
I have a ShellVM which is the main VM for my app. It dishes out navigation and props that my main view binds to.
Then I have a ManageVM that does all the grit work for managing the client, stores, imports, exports etc. It also handles navigation of all my management views.
Then I have an ImportVM that fleshes out the importing of data.
I also have a static PageValues dictionary that stores pages and specific properties and values that should be retained when switching views. It also stores any 'global' properties that is used throughout certain VMs.
I'm using Messaging to pass data between the VMs. The validation and prompts (using dialogs) of the PageValues data is controlled in my ManageVM. I placed it here as I feel my ManageVM should handle all 'management' like setting the client and store. Setting the actual values is done by sending a message to the ShellVM that handles this.
The ShellVM handles the CRUD of the PageValues. So in other words, if any VM gets or sets a global/shell-wide property, it does so by means of messaging to the ShellVM. The ShellVM then sends the message/result back to whichever VM requested it.
Question
This feels very spaghetti-like. I've got a ManageVM that does the loading and validations on PageValues that are actually CRUD'ed in the ShellVM.
Am I on the right track or is there any other suggestion I can try to make this feel a bit cleaner?
Thanks for reading.
Edit
What I'm trying to achieve is to have a container that holds values (ie client and store) that could be accessible from multiple VMs. A bonus is to have each page's/view's values in this container too. Then on showing of the view, it will grab its values from the container and populate the view.
You said
if any VM gets or sets a global/shell-wide property, it does so by
means of messaging to the ShellVM
I propose an interface based approach instead of message passing for this purpose. ViewModels passing messages is for view models to communicate,not for setting a global state. If there is a global state of the application,it is better handled through a dedicated service, IMO.
public interface IApplicationService
{
//your applcation methods here
}
public class ApplicationService:IApplicationService
{
}
public class ManageVM
{
public ManageVM(IApplicationService){}
}
public class ShellVM
{
public ShellVM(IApplicationService){}
}
public class SomeOtherVM
{
public SomeOtherVM(IApplicationService){}
}
Yes, this does sound rather messy. You need to try and isolate areas of functionality into their own VMs so they are not dependent on one another.
One of the tricks I use to do this is to try and imagine that I suddenly need to copy a blob of functionality (say one of your pageviews) into another application. How easy would it be? Would it be a case of just copying one VM and injecting a few dependencies? Or is the VM impossibly coupled to the rest of the app?
It's a bit difficult to give advice without knowing exactly what your app is doing, but really you want each PageVM to be in charge of it's own validation, and CRUD. Or, if the data is shared between many pages, then you need to pass in some kind of repository than the PageVMs can query for data. If validation logic is specific to some data, then put it on the model itself and just leave the presentation of that validation to the VM.
For global settings, I tend to pass around a settings object rather than using messaging.
Have a read up on inversion of control, and dependency injection. These can help you to keep objects loosely coupled because you can see exactly what other things your object is depending upon by looking at the constructor. If you are passing in half the application then it can serve as a warning alarm to try and reduce the coupling.
Related
I heard its the next best thing in building WPF UIs, but all existing
examples have dozens of lines of code - can I get a Hello World
for MVVM that explains in no uncertain terms what its all about?
I'm fairly new to C#/.net as well, so maybe point me to some
resources that could help too?
Much appreciated!
One sentence explanation:
MVVM is a reimagining of the well loved Model-View-Presenter (MVP) pattern that is designed to work especially well with databinding facilities supplied with WPF to separate application logic from UI design.
Longer, more useful, explanation:
The basic concept of MVVM is the break apart a WPF application into separate components each of which has one responsibility in the process of getting information on screen.
Firstly you have the model. This is a class with very limited functionality that is generally populated from some outside source such as a database or webservice. For example:
public class MessageModel
{
public string Message { get; set; }
}
On top of that you layer the ViewModel, this is where the logic of the application sits, it notifies the view of changes to the model and ensures data consistency. By implementing the INotifyPropertyChanged interface two way databinding between the ViewModel and the view is given for free by WPF:
public class MessageViewModel : INotifyPropertyChanged
{
private MessageModel _model;
public string Message
{
get { return _model.Message; }
set
{
if (_model.Message != value)
{
_model.Message = value;
OnPropertyChanged("Message");
}
}
}
}
Finally you have the View. This is a xaml file that describes the layout of the controls used to display and edit the data in the ViewModel:
<Canvas>
<TextBox Text={"Binding Message"} />
</Canvas>
The reason that you go to all this effort is that the Model is very lightweight and easily passed across domain boundaries. It is simple to send or receive it from a webservice or map it to a database table. The ViewModel, on the other hand is complex, but has few dependencies - it doesn't care where the model gets it's data from, only that it is there and it has no concept of a view at all which makes it very testable (the logic of your application doesn't rely on a UI to test). Finally the xaml is well compartmentalised and can be handed off to a designer who needs to know nothing about the logic of the application, only that the ViewModel will present certain data under certain names. This encapsulation makes it very easy to define roles in large projects, or put together a limited UI to test logic against while the real one is being polished.
MVVM is a star-fan relationship. The fan knows the star but the star does not know the fan. The fan loves his star so much that if the star changes himself ( I mean his dressing style ), the fan changes himself accordingly.
Now replace "star" with "ViewModel" and "fan" with "View" and read it once again.
One sentence? Here goes.
MVVM is a UI segregation pattern where the Xaml (View) binds to a facade (View Model) allowing the guts of your program (Model) to avoid having UI concerns leak down a layer.
The simple statement that helped me get my head around it best was "Could I unit test my business logic without the user interface?" I think this should be the question you ask while learning and designing using MVVM concepts.
This site has a great diagram that explains it.
Basically you have 3 components:
1) Model - The data model of your application. this is pretty standard and the same as any MVP or MVC app.
2) View - The XAML that defines the view/layout of your app.
3) View Model - Because WPF demands that the view attach to things in certain ways (like requires that collections implement INotifyCollectionChanged and stuff like that) it normally requires that you massage your data a little bit to get it in a form suitable for the view to display. This is where the view model codes in. It packages up the data into view models that the view can easily display. This is what your view XAML will bind to. It must respond to events from the model layer and update itself.
(Then your controllers hang on the side somewhere - ideally using WPF commands - and make changes to the model, which fires events to update the view model)
a pattern where the frontend(view) and backend(modal) communicates (back and forth) using a common mediator(view-modal).
The MVVM pattern is when the UI interfaces with an xaml-friendly intermediate object to get at your xaml-unfriendly actual data.
I would say something like: "Presentation pattern for separation of concern between user interface and it's logic"
An improved answer:
MVVM is all about the future; you want to separate your application logic from the framework so that either the framework can evolve, and your app may not have to change, or your app can evolve and you won't have to worry so much about changing the actual UI aspects.
Actually, MVVM is a refinement of a pattern that has been around for some time. I can remember evolving the pattern when I was working in MFC. There are at least two reasons for doing so. MFC or <> is fairly complex, and mixing MFC constructs in with your application logic makes the application kind of brittle. Example: replacing a listbox with a combobox (or selector in modern terms) is much more difficult if the logic for supporting the content of the list/selector is combined with the logic to manipulate list/selector itself.
Some really good one-sentence (or close to it) explanations already. I'll just add to it by saying that if you're past the basic level and you want an example of how to use MVVM in a real-world app that has menus, tool bar, options dialogs, docking tools windows, etc., take a look at SoapBox Core and this demo using SoapBox Core. It is open sourced so you can get lots of ideas.
Because you can't data-bind to your own codebehind
(only half joking here)
I've been giving this some thought lately and I was hoping someone who has better knowledge of MvvmCross than myself can shed some light on this. Given the nuances between each mobile platform there are probably a few different factors that can affect this problem. But for this scenario let's assume we want the best approach for a cross platform solution.
So let's say we have a basic View and a ViewModel class setup. Here's an iOS example.
View
public partial class FirstView : MvxViewController<FirstViewModel>
{
public FirstView(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
Request = new MvxViewModelInstanceRequest(FirstViewModel.NewInstance());
base.ViewDidLoad();
}
}
View Model
public class FirstViewModel : MvxViewModel
{
public static FirstViewModel NewInstance()
{
return Mvx.IocConstruct<FirstViewModel>();
}
public FirstViewModel()
{
}
}
Now at the loading of this View or at some point just before the view is created we want to fetch some data from the web using a service that we inject using dependency injection; because the displaying of the view depends on that data. Here lies the problem.. at which point from a platform perspective and in the MvvmCross lifecycle would be the most appropriate place to call the web fetch function in the service.
With regards to platform I would assume that we should do it once the view loads. Because if the fetched data is anything other than simple data types it will be inconvenient to work with on Android, as one would have to persist the data to disk and retrieve it after the navigation, due to serialization between activities.
So assuming we called the web fetch during the view loading process. Where is the best place in the MvvmCross architecture to fire it off, that most closely follows the design paradigms. e.g. The View Model. Is there any lifecycle methods that someone could recommend to call it inside as well. Something like the Start method, called after the view model has been created.
First of all, I don't understand why you won't let the platform itself instantiate and do it's ViewModel lifecycle instead of creating a new instance of the ViewModel using Mvx.IocConstruct. That method does not invoke the ViewModel lifecycle and will not call neither Init or Start on the ViewModel.
If you let the platform do this for you, first the Init method will be called with the arguments that you set when using ShowViewModel<T>(args).
When ViewDidLoad invokes the Start method will subsequently be called.
This gives you two places to invoke the Service that you inject in the ctor of the ViewModel.
If you want more control over when to download the data, you could create some ICommand's, which you invoke on your ViewModel in any of the ViewController lifecycle methods. This could be in the ViewWillDisappear/ViewDidDisappear method, or you could fetch the data.
There are so many ways you can do this. In the end it is entirely up to you, and you can't possibly know when a user decides to change to another View. However, you can make qualified guesses and try fetch data before the user actually wants it.
There is a nice article for you to read here, by Rob Gibbens on how you could do Resilient network services. It describes how you could speculatively fetch resources based on what the user is doing, and this way have something ready for the user to see when he enters the View. This could be cached data or fresh data that you are fetching after showing the cached version.
In any case, I would suggest you stop loading your ViewModel's with Mvx.IocConstruct and let MvvmCross handle this for you in order to get lifecycle methods invoked.
I am attempting to develop a little program which will communicate with a device on a serial port. The program will be responsible for formatting user entered data and reading and presenting values received by the device. I am pretty new to WPF and MVVM and have achieved a basic understanding of the whole databinding / XAML mess (I think).
Currently my understanding goes something like:
View: UI only stuff. Binds to ViewModel.
ViewModel: Takes a model or various properties of a model and presents them in a way that the View can understand. Also provides a way for the view to modify the model.
Model: The data the UI presents and modifies.
Now I am at a loss as to what provides Models to the ViewModel such that the application as a whole is aware of changes to Models.
The Model currently looks something like the following. My device takes calibration records and can read back all the calibration records.
public class Device : ObservableObject
{
public ObservableCollection<CalibRecord> CalibRecords { get; set; }
private SerialPort sp;
public Device(SerialPort port)
{
this.sp = port;
this.CalibRecords = new ObservableCollection<CalibRecord>();
}
public void WriteCalibration(CalibRecord record)
{
/* Write a calibration record to the device */
}
public void ReadCalibration()
{
/* Read all calibration records from the device and update CalibRecords */
}
}
I am struggling for a place to put this guy so that it can be accessed by the entire application. Currently I instantiated it in the main window's ViewModel but then it can't be accessed by other ViewModels unless I inject it into the constructor. This is fine for a couple classes but gets unwieldy quickly the more classes a ViewModel needs.
Perhaps this is what the so-called "business logic" or "service layer" is. Can you help me understand where to put the business logic in an MVVM app? Or, do you guys have some examples I should look at that focuses on the whole application (particularly the business logic) and not just the MVVM stuff?
Your understanding of MVVM is correct, but the "textbook description" doesn't account for services. Typically this is done with dependency injection (DI). Define an interface, IMyDevice and implement it in a MyDevice class. Then register it with your DI container IMyDevice -> MyDevice. By using a DI container (properly) you'll also take yourself out of the VM construction picture. You would have a VM something like:
public class MyViewModel : ViewModelBase
{
public MyViewModel(IMyDevice myDevice)
{
}
}
to get an instance of the VM, you would do:
theDIContainer.Resolve<MyViewModel>();
and it would new up the MyViewModel class and automatically resolve and pass in the IMyDevice instance for you.
There is a lot more to DI then I covered here... just a basic 10,000 mile high answer to your question. Read up on DI and see how it comes into play with MVVM.
The mindset of MVVM is to separate in a loosely coupled manner layers, allowing each to be modified and tested without interfering with the other.
You test the ViewModel and mock the Models. You test the Models. Your Model may take form of several services automatically injected by some DI container. Subsequently there is as little as possible friction between the Models, the ViewModel. Eventually they may be deployed independently; this lowers maintenance and cost; that's the same mindset of that of microservices.
For instance, you might have a Model that is tested and can be used for a WPF app, mobile app, web app, etc. Your ViewModel however should not a priori be involved in another GUI. You can update your webapp without commit/deploy for the other and the Model; lower cost, lower duration commit-to-deploy (including testing).
When you start with cohesive classes and test them, it will be clear where to put what.
It's OK to have only a View and a ViewModel; though the Model should have the business logic if it's enough rich; you should have tests for the Model, tests for the ViewModel ( behavior of the UI). The VM and the Model layers can be much more complicated than just 2 classes, you may have multiple (automatic) dependency injections (check the excellent Dependency Injection in .NET, Mark Seemann).
Subsequently, logic (for your business) should go in the Model, not in the ViewModel; logic for the UI should go in the VM.
Regarding WPF, the View take the form of a UserControl with View.xaml (what you see) and View.xaml.cs (the code-behind); not all UI logic goes into the ViewModel; pure View logic goes into the code-behind. The code-behind contains in particular all the dependency properties, behavior logic (shared with the xaml code) etc.
I have a view model which should check that label of a new entity is unique (not in DB yet).
At the moment I've done it in the view model class:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (PowerOrDuty != null)
{
if (PowerOrDuty.Identifier == null)
{
using (var db = new PowersAndDutiesContext())
{
var existingLabels = db.PowersAndDuties.Select(pod => pod.Label);
if (existingLabels.Contains(PowerOrDuty.Label))
{
yield return new ValidationResult("Cannot create a new power or duty because another power or duty with this label already exists");
}
}
}
......
Please note that this is a small internal app with small DB and my time is limited, so the code is not perfect.
I feel that DB access from view models might be a bad practice. Should view model have direct DB access? Should it be able to call a repository to get the available labels? Should validation requiring DB access be done in a controller instead?
Should view model have direct DB access?
I think this should be avoided at all cost
Should it be able to call a repository to get the available labels ?
This is not the concern of a ViewModel.
This would introduce some complexity in the testing of your ViewModel (which should almost need none) I guess it is a sign of trouble coming.
Should validation requiring DB access be done in a controller instead ?
Maybe, if by "DB" you mean "Repository". But what comes to mind is a separate custom validation class that you will be able to (un)plug, test, and reuse, in another controller for ajax validation, etc
I think that accessing DB from VM is not wrong... AFAIK it is not breaking MVC concept (since it is a presentation layer concept). Said that, it could be better if you have the Validate method provided by a Service Layer.
But all the logic related to the content of the ViewModel, it is better kept in the VM than in the Controller. Cleaner controllers is better.
Your view model should not be tied to your context, it only cares about displaying data and validating it after a submit. You can perform validation like a required field or a value in range, but you can't know if a label already exists in your database.
You can't also fetch a list of "forbidden labels" before displaying your form, in order to test your label afterwards, because that list could have changed during this time (another user updating you database).
In my opinion, validation at model level should focus on what it can validate without knowledge of the data source, and let your database notify you errors like submitting a duplicate value in a field which has an unique constraint. You'll catch exceptions coming from your database for errors like those, and manage them accordingly.
Anyway, i think there's no straightforward answer for a problem like this.
I personally like the ViewModels to be anemic -- simply classes with properties.
For custom server-side validation like this, I prefer it go either in a service, with the consumption of the service in your controller, or even behind a custom validator.
With a custom validator, you could even (optionally) execute the validation remotely. That gets a little more complex though, but I've done it using a generic remote validator that consumes an Ajax action method to perform the validation, and wire that up through both the client validator and remote validator (to ensure you have your validation logic in a single method).
But which ever way you go, I think it is more common -- and in my opinion, more clean -- to keep all logic out of your ViewModel. Even in a simple app, your ViewModel should be dumb to your database context. Ideally, only services (not necessarily web services, but just an abstraction layer) are aware of your database context.
This, to me, should be done regardless of the size of application. I think the effort and complexity (it only adds another assembly to your solution) is worth the abstraction you get. Down the road, if you happen to decide to consume your services from another application, or if you decide to swap out your database context, it's much easier with that abstraction in place.
I have a control in which we show some links to different sites based on some business rules. Currently all business logic to build link list is in control.
I plan to move out the busincess logic from the control.
what will be a good design for this?
can I use any design pattern?
You shouldn't get too caught up in thinking about patterns. Most of the time they are overkill and add too much complexity. Particularly with a trivial scenario like this.
Just utilize good object-oriented practices and you'll be fine. Encapsulate your business logic in another class and provide public properties for your control to access it. Keep it simple!
How about the Model-View-Presenter pattern?
Another good choice might be the Mediator pattern.
Do you really need a custom control for this?
Model-View-Controller suggests that you only have display logic in a control.
Find a solution that allows you to make small changes to a built in control (ListView) and create a custom data set somewhere else to pass to it.
I not sure how you implement your business rules but here is an idea...
I would databind your web forms list control.
public class YourLinks
{
// You could do it by overloading the constructor...
// Again not sure how you determine what links should be displayed...
// If you had consistent types you could make your constructor internal
// and then create a YourLinkBuilder see below...
public YourLinks(User user, Region region)
{
}
public YourLinks(City city)
{
}
// Databind to this method...
public IEnumerable<string> GetLinks()
{
// return your links...
}
}
public class YourLinkBuilder
{
public static YourLinks BuildPowerUserLinks()
{
return new YourLinks(new PowerUser(), new Region("Washington"));
}
public static YourLinks BuildVisitorLinks()
{
return new YourLinks(new VisitorUser(), new Region("Empty"));
}
}
Given the little information provided, I would suggest you create a model of just the links (and its related data). So that you can pass the LinksModel to your views for rendering. Or pass your LinksModel to your existing model (as a sub-model).
Either way, all this data is encapsulated. So if you want to add data to it later, it will not change your method signatures (or general contract). If you want to remove data from it, same advantage. If you want to remove it entirely, its only one object and simplifies the removal.
You can also build links view renderers so that it and only it knows how to visually display the LinksModel. So within your view, you can delegate the visual aspects of the links info to such renderers instead of having logic within your existing view. If you want to change how links view looks later or want to give the user the power of selecting different renditions, you can simply use different renderers rather than jamming your entire code with 'if' blocks.
Jeach!
You should use Model-View-Presenter for sure. In the view, you should have your control.
The control's responsibility should be merely to take input from the user, validate it, and pass that information to the presenter. The presenter should then interact with the model, where your business rules are stored.
From the model, you may wish to return the links that are then passed to the control for display, or you may wish to return some metadata that is passed to another system to retrieve the links.
What I would do is use the Strategy pattern in the model, so that you can easily swap in and out different versions of your business rules.
To abstract interaction with your backend datasource (if you have one) have a look at Martin Fowler's Gateway pattern.