I have a ListView and a Popup which content(Buttons, TextBoxes etc.) changes dynamically depending what is selected in the ListView. Is it legal, if the View determines what is in the Popup or the ViewModel should do it? I also would like to ask, whether the View can handle the ViewModel's events?
MVVM is not a law - it is a tool. If what you are doing serves your purpose - it works for you. If you are asking what the best practice is - it depends on why you using MVVM in the first place.
Is it because you want to write tests independent of the view? Then put your logical state in the view model.
Is it because you want to be able to display design time data in Blend? Then put your logical state in the view model and define design time data to show in design mode.
Is it because you want to have maintainable code that will be maintained for a long time by people familiar with MVVM? Put your logic in the view model.
Is it because your app is complicated and you would like to have separation of concerns so different people would work on the view and different people would work on the view model. Put your logic in the view model.
If none of these apply - you might be just fine and spend less time trying to figure it out by just putting the code in code behind and not let MVVM to be a drag.
If your problem is how to drive the contents of your Popup with your view model - you can typically do that using a combination of ItemsControls such as ListView, GridView or maybe a custom one and ContentControls with ItemTemplateSelectors or ContentTemplateSelectors that implement the logic of determining which view to display based on the view model state.
Also check my Minimalistic MVVM manifesto post.
Check out 5: Implementing the MVVM Pattern for a detailed explanation of what is valid in the View. It explains it a lot better than I could here in this answer.
I will give a shot at your questions though:
Q: Is it legal, if the View determines what is in the Popup or the ViewModel should do it?
A: The view should determine how the Popup is displayed, the ViewModel should determine what is displayed.
Q: Can the View can handle the ViewModel's events?
A: Absolutely, this is a key part of DataBinding - handling INotifyPropertyChanged events.
Related
I'm new to WPF and MVVM and attempting to write a firmware programmer so I can update stuff via USB and save and upload setting/state data. MVVM seems like it could work for this. I currently have pages and can navigate around the app (although the nav service is in code behind for now) but I'm stuck on how to implement things that aren't in the standard 'customer'/'person' examples.
On a couple of pages, there are subsections that I can see being sub-divided into separate views hosted in the page, and these subsections are used more than once in the app.
For instance, I want to have a TextBlock that displays the connection status and updates based on signposts in the connection process, firmware update, backup, etc. Progress bars with the % are another. Sections that are used to display errors, data or a selection box depending on what happens connecting would be another.
Having a sub-section house 3 completely different outputs all stacked on top of one another and shown based on the situation seems messy. I can see that section being a ViewBox and creating a unique view for each case being a better solution there (and possibly the other examples above).
Or take the 'status display', I can see implementing it as it's own view and the page's view model will use a messenger to pass the current status back to the 'status display' view model. I can also see it all just handled by the page's view model via calls to it's own methods. I can also see potentially using a global model to hold the status strings (maybe an enum?) and the view model can be made to pull the correct string into a 'currentStatus' variable.
What is the proper way to approach this? Keep it all a single page? Subdivide the dynamic/changing parts from the static parts?
OP:
Obviously the pages themselves are views, but would it be best to have the 'Status:'display TextBlock and it's value, and the Error/selector section be views also?
If you are asking whether the status and error displays should be UserControls then yes they can be "a view" irrespective of whether the control is using a view model or not.
Incidentally, it is generally better to use DependencyPropertys instead of view models in a UserControl otherwise you will end up having duplicate properties in both the view (so that MainWindow can databind to it) and in your control's view model (purely for the benefit of the user control).
If your UserControl uses DependencyPropertys then both users of the control and your view can both databind to the same set of properties without duplication. In this way you will realise that UserControls have no need for a separate VM.
OP:
...the page's view model will use a messenger to pass the current status back to the 'status display' view model...
Don't do this, this is what data binding is for.
I have for the last few month been trying to familiate myself with the mvvm pattern in wpf. This is a topic that is widely discussed and i have come across articels which in places contradict one another. I know mvvm is a pattern and not a universal truth however do in certain case find thesse grey area of deciding what goes where, and what does what. 99% of the time it is between the viewmodel and view these problem arises.
my current mindset for deciding what belongs where:
Model: it only contains data which is to be saved to a file. Nothing More, nothing less.
ViewModel: is a communication bridge between a view and one or more models associated with that view.
View: handles visual representation, visual popups and visual modifications
first of af simple question concerning the Model: (Case 1)
In every implementation i have seen so far the model object is class implementing the INotifpropertyChanged. Why should the model be a class and not just simply an interface describing what the data should be and let the viewmodel implement this interface? The model should not deal with the ui even if it is decoupled and therfore giving a model class the INotifyPropertyChanged is just as wrong as making the viewmodel inherit from a DependencyObject (even though i understand its importance in that type of model implementation)?
Grey area example of what the ViewModel should handle vs the View: (Case 2)
Say i am creating a Uml editor where there are Nodes and Connectors Created in a viewModel and kept in thier own ObservableCollection.
<SomePageView.DataContext>
<vm:SomePageViewModel/>
</SomePageView.DataContext>
<Grid>
<ItemsControl ItemsSource="{Binding Nodes}" DataTemplate="{Binding SomeNodeUserControl}"/>
<ItemsControl ItemsSource="{Binding Connectors}" DataTemplate="{Binding SomeConnectorUserControl}"/>
</Grid>
When a node is dragged around the grid any attached Connector endpoints will follow the node around as it is moved. I personally see this as Comunication between the UiElements, but there are 2 fundamentally different ways of implementing this type of behavior. Update the Connector by keeping a complete reference to the NodeviwModel and use its position members to update the position of the Connector. It is a pretty simple approach however do not like it as i believe it should be the ConnectorView that update the postion of The ConnectorVm. this requires that the Connector View know something about a specific NodeView. However this approach more complicated and i havent found a valid solution for it yet ( currently looking into the EventAgregator pattern). The Reason why i like the last aproach is that if select a connector it should be the view that dictates how the connector can be moved around and not the ViewModel. Any comments or advice on my observations?
in the mvvm pattern were should ui patterns be kept: (Case 3)
in mvvm where should the eventAgregator, Mediator be used. in the ViewModel or the CodeBehind? My current belief is they belong in the code behind, but i have a shred of uncertainty regarding this matter. If kept in the codeBehind i csn imagine a cleaner aproach by using the The VisualTree with the loadedevent instead of using constructors taking arguments of Eventagregator and likewise.
Similar i can implement an UndoRedoController which would not require to be a singleton. should be easier to test, possible to have more UndoRedoControllers existing. An example could be a document program that allow mutiple documents to opened at once in tabs and therfore should have thier own UndoController.
Case 1
In M-V-VM the ViewModel always (Model not always) implements INotifyPropertyChanged
Model can but doesn't coz you really don't want to pollute Model with a fairly WPF specific feature like INPC .
The model should not deal with the ui even if it is decoupled.
INPC interface is not UI specific! It simply informs of a change. Indeed WPF heavily uses this to identify changes, but doesn't mean it is a UI interface.
Case 2
View is responsible ideally for just the representation of data.While dragging is an action on the view,the UI/data updation in the view/ItemsControls are based on the decisions of viewmodel.
There is no harm in using the code behind if the implementation is comparatively easier and logical as in ViewModel, but if you can accomodate the same in viewmodel,you should.
Case 3
It should be in the view model.
If kept in the codeBehind i csn imagine a cleaner aproach by using the
The VisualTree with the loadedevent instead of using constructors
taking arguments of Eventagregator and likewise
Using events, will result in a tight coupling between views that makes the application harder to maintain. It could potentially also lead to memory leaks if the main class(publisher) of an event lives longer than a visual controls/usercontrols(subscribers) and you forget to, or don’t know when to, unsubscribe from an event.
I have multiple of views (user controls), each with its own ViewModel. To navigate between them I am using buttons. Buttons display image and text from corresponding view model and also need column and row (because there are like 10 views: 10 columns with different number of rows each).
Right now buttons are created dynamically (I made a Navigator control for this) and for view models I have base class to hold text, image, column and row. Number of views available will be different (depends on user level and certain settings), that's why it's I need control here.
Question: how shall my control get data from view models?
Right now I have interface INavigator, defined in (lol) control itself. And view models implement it. I could go opposite, let my control to know about view models. Both looks wrong.
There is a single Navigator control what has, lets say, Items bound to a list of view models. It can cast each view model to INavigator or ViewModelBase (common for all pages) to obtain specific view model image, text, column and row. So either view model knows about control (to implement INavigator) or control knows about ViewModelBase.. And this is a problem, both solution bind tight control and view models, which is bad in mvvm.
Schematically
The way you've drawn your diagram answers your own question as to how you should structure the code for this.
What you need is one VM (let's call it MainVM) which contains an ObservableCollection<VMBase> of the other VMs (using your base type so that they can all happily live in the same collection).
Your View needs an ItemsControl (bound to your ObservableCollection<VMBase>) where you specify a DataTemplate for the Button using the properties exposed by the VMBase type only. Set the Command property in the Button to call SwitchCommand, CommandParameter is set to the item itself (i.e. {Binding .}).
Your View also needs a ContentControl bound to a SelectedVM property on MainVM which you can populate.
Implement SwitchCommand to set the SelectedVM property based on the value from the CommandParameter.
public void ExecuteSwitchCommand(object parameter)
{
var vmBase = parameter as VMBase;
if (vmBase != null)
SelectedVM = vmBase;
}
All properties mentioned here should be INotifyPropertyChanged enabled so that the View registers when they change and updates the UI.
To get the different UIs for the ContentControl, add type-specific DataTemplates for each of your specific VM types to the Resources file of your View (or if you're smart and are building a custom plug-in framework, merge the Resource Dictionaries).
A lot of people forget with MVVM that the whole point is that there is a purposeful separation of View from ViewModel, thus meaning you can potentially have many Views for a single ViewModel, which is what this demonstrates.
I find it's easiest to think of MVVM as a top-down approach... View knows about it's ViewModel, ViewModel knows about its Model, but Model does not know about its ViewModel and ViewModel does not know about its View.
I also find a View-first approach to development the easiest to work with, as UI development in XAML is static (has to be).
I think a lot of people get to wrapped up in 'making every component (M, V, VM) standalone and replaceable', myself included, but I've slowly come to the conclusion that is just counter-productive.
Technically, sure you could get very complicated and using IoC containers, create some ViewLocator object which binds a View-type to a ViewModel-type, but... what exactly does that gain you besides more confusion? It makes it honestly harder (because I've done this at one point) to develop because now you've lost design-time support first and foremost, among other things; and you're still either binding to a specific view model interface in your view or creating the binding at run-time. Why complicate it?
This article is a good read, and the first Note: explicitly talks about View vs. ViewModel. Hopefully, it will help you draw your own conclusions.
To directly answer your question, I think having your ViewModels implement an INavigator interface of some sort is probably ideal. Remember your VM is 'glue' between your view and model/business logic, its job is to transform business data into data that is consumable by your views, so it exists somewhere between both your UI and business layers.
This is why there are things like Messengers and View Services, which is where your navigator service on the ViewModels can fit in nicely.
I think the design has led to a no way out situation.
I believe that creating a custom button control where the dependency properties tie the image, the row and column actually provide a way for the page, which it resides on ,to get that information to them; whether they are dynamically created or not.
Continuing on with that thought. There is no MVVM logic applied to a custom control, the control contains what it needs to do its job and that is through the dependency properties as mentioned. Any functionality of the button should be done by commanding; all this makes the button data driven and robust enough to use in a MVVM methodology or not.
Question: how shall my control get data from view models?
There should only one viewmodel which is the page the control resides on. The control is simply bound to information which ultimately resides on that VM. How it gets there, that is up to the programmer. If the button is going to contain state data, that is bound from its dependency property in a two way fashion back to the item it is bound to.
By keeping VMs out of the buttons and only having one VM that is the best way to segregate and maintain the data. Unless I am really missing something here....
Same as others here I find it a bit hard to actually understand what you are asking, so this is quite general. The answer to the question header is simply: the Control gets the data from the ViewModel through bindings, always. You set the DataContext of your Control to the corresponding ViewModel, and from there you keep the ViewModel and the Control synchronized:
If you add an ItemsControl containing buttons to the View, you add an ObservableCollection<ButtonViewModel> to the ViewModel and bind the ItemsSource of the ItemsControl to this.
If you allow the user to dynamically add content to the View, the actual code that does it resides in the ViewModel, e.g. when the user clicks on a button "Add Button", you use the Command property to call a ViewModel method that adds a ButtonViewModel to the collection and the View will automatically reflect your changes.
There do exist complicated cases that are impossible to code exclusively in the ViewModel, I have found Behaviors to be the missing link there, but I'll get into that when you show me the specific case.
If you'd like to get a working example, please provide as much code as you can, with your exact expectations of what it should do.
Should I always use Command even though it might not be necessary?
Or should I only use Command in the case where more things, menu items, buttons,
whatever, when clicked execute the same code?
Maybe it is good practice to always use Command, or maybe it adds additional
unnecessary complexity. I am new to WPF so please share some advices.
If you're using the MVVM pattern, which is mandatory in every serious WPF application, 'ICommand' is the way to go for every action that is not purely interface logic.
I'll explain:
As you probably know, the MVVM pattern distinguishes between Model, ViewModel and View, where the ViewModel mediates between Model and View. The ViewModel usually holds all the data which is consumed by the view and which you bind your view to. The important thing is:
The View is agnostic of the ViewModel
This means, although your View is bound to the ViewModel, it doesn't reference it, there is no logical dependency to the ViewModel. The 'ICommand' bridges this gap: It kind of packs an action into a bindable property. That's the main point, probably:
A command wraps up an action or function into a WPF databindable
property
And as databinding is the mechanism which, in MVVM, View and ViewModel are connected with each other, the command is the vehicle to perform every action, no matter if it is triggered by one control or by many, that transcends the sphere of pure UI (which is almost everything):
Have a look here (MSDN), where this image is taken from:
If you don't use MVVM I'm not sure whether you need commands at all. There is no significant difference to WinForms then, regarding the UI event handling. But again: MVVM and WPF go hand in hand, in my opinion.
I am in the process of re-writing one of our large Silverlight apps to use PRISM and the MVVM design pattern.
A very common scenario is a DataGrid in the View. Double clicking a row allows the user to edit the entity represented by the row, using a ChildWindow.
I am tempted just to capture the DoubleClick event in the code behind, create a new ChildWindow of the proper type, and set the DataContext to be DataGrid.SelectedItem.
I know that this is not the proper way to handle this scenario with PRISM and MVVM, however.
I would love advice on what is! (re: my title...it seems like InteractionRequest might be the best way to do this?)
Thanks...
EDIT: We did end up deciding to go with InteractionRequest for our solution. We almost always use "Notification" as the type and pass a new ViewModel (each ChildWindow has its own) as the Content.
In our case the ChildWindow view was complex enough to warrant its own viewmodel. This view isn't too closely coupled with the data grid view.
So, we have an EventTrigger attached to the data grid (we actually use Telerik's data grid) in XAML. The event trigger executes a command in the view model using InvokeCommandAction.
The command publishes an aggregated event that has the selected item as the payload. The event is picked up by the central application controller that is responsible for creating the ChildWindow view and a corresponding view model (using the event payload as the context).
I think that interaction request could potentially be used in your case, but based on my understanding the idea behind an interaction request is a very simple Ok or Yes/No interaction. You might be pushing the boundaries with a bunch of text boxes, validation, etc.