Caliburn Micro, Multiple views from a single view model - c#

I have an application that I am currently working on and there is a requirement to change the view based on an event occurring. This event means that the same ViewModel must be used but using a different View. I do not currently know if this is possible to do with Caliburn but I imagine it should be. the main problem I am having is the convention over configuration element of Caliburn. Example:
I have a ViewModel "MainViewModel" and it is bound to "MainView" through convention. When the event occurs I want the application to be displaying "MainView2" instead of "MainView". I can imagine there is a programmatic way of setting this but my inexperience with Caliburn is a problem.

You can control which View is used for your ViewModel by setting cal:View.Context property on ContentControl that shows the view.
Have a look here.

Related

How does MVVM fit into WPF when you must refer directly to a control

I'm new to WPF and I'm attempting to incorporate MVVM design pattern into my projects. In all the MVVM examples I've seen, the MainWindow.xaml.cs is only used to set the DataContext to the view model.
this.DataContext = viewModel;
Everything is very neat and decoupled away from the UI. events were also replaced with commands. There are two questions that I have regarding this.
I'm wondering about how you are supposed to hook up controls that don't have the command property.
What am I supposed to do when I would typically interact directly with a control e.g. Perhaps I want to set a combobox's index to -1. How am I supposed to do this on the view model?
The collected comments by #EdPlunkett, #Clemens and #BionicCode answered my questions.
To Summarise:
I can interact with controls by binding to their properties through INotificationChanged and ObservableCollection
Elements that don't have a command property can still have properties bound to an ICommand property in the viewmodel.

Modern UI CommandBinding

I have a little problem with my modern UI application. I can'T figure out how can I run a simple Button Commmand Binding in Links Group, because i don't want show a new page . I only want run my Logout code in code behind with Command Binding.
Example what I want
Ofcourse,I know this is just an idea that does not work. I only search a possible solution.
can someone advise something?
Your command needs to be a property and the DataContext of where you are trying to use it needs to be set to where your property is stored (typically in a view model). If you are using the code behind you can set the data context to the window or user control (whichever it is) and have access to the property for binding purposes; however, this is a bad practice and you will benefit more from using a view model.
So in short, create a view model with your command as a property. Set the DataContext to the view model and then bind to the property.

How to use a button while also using a DataModel in WPF

I'm creating an application in WPF using MVVM. I have a tab called tab1, which is a UserControl and has an associated DataModel (but no View, and thus, no ViewModel). Within tab1's content, there is a ListView, inside which is a button. The problem is that I would like the button to work. It worked when tab1 had an associated Tab1ViewModel, but I am told it must have a DataModel and not a ViewModel. I don't believe DataModels can support commands, so does anyone know of a workaround for this? Or does there really just need to be a ViewModel for any nested control with buttons?
Not having a view-model associated with the view is "kind of" against the guidelines of MVVM.
I can think about two solutions :
If you are "allowed", you can inherit the DataModel and add some
"ViewModel functionality" (Like the button's command)
If you are "allowed", have a view-model that contains the data-model (in this method you lose the ability to listen property changes if bind your view to the nested data-model fields)
Add the event handler in view's code-behind (which is against the MVVM's guidelines)
These two solutions aren't that great so I suggest that you try to solve the issue that leads to the facts that you can't use a view-model with your view and solve that.

How can control in the view get specific data from view model?

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.

MVVM in WPF how to communicate with the viewmodel

I guess I am still a little hazy on how communication goes in MVVM. I read that you are not supposed to use events to communicate with the viewmodel, so i assume that you send a command.
However, commands actually bubble up within the visual tree (the view), right? so then it may reach some target control that can handle the command. Does that target control then have a viewmodel that can modify the model?
Sorry, I'm really confused about how to get commands from the view to the model. I assume that getting information the other way is just a simple matter of having the model implement Inotifypropertychanged to tell the viewmodel that it has changed and then have the viewmodel implement inotifypropertychanged so that the view can bind to the viewmodel and have the properties update.
http://blogs.msdn.com/blogfiles/erwinvandervalk/WindowsLiveWriter/ImplementingtheModelViewViewModelpattern_D996/image_14.png
Not all commands bubble - those are RoutedUICommands, which are just a particular implementation of the ICommand interface provided by the framework. You can implement your own ICommand objects that have custom behavior and act just like normal objects (no bubbling, tunneling). If you create them in your ViewModel, certain View objects like Buttons and MenuItems can bind directly to them through their 'Command' properties.

Categories