One ViewModel, multiple views - wpf

I am having a hard time getting multiple views to work against 1 viewmodel. I have read Naming Convention for Multi-View Support without getting much out of it, and have tried countless things in the process.
Just to take a simple example. Say I have a ViewModel for People residing in ShellViewModel, which basically contains a list of Person-objects. I want to display them in two different ways in my application.
What is the correct way to name the Views in this case, and how do I display both views in ShellView?

Anders is correct, there are a number of default conventions for Caliburn.Micro, one of them will locate and display <RootNS>.Views.[<ChildNS>].<ViewTypeName> for <RootNS>.ViewModels.[<ChildNS>].<ViewModelTypeName>.
In your case, for a single View (assuming the classes reside in namespaces derived from the folders):
<RootNS>.Views.PeopleView would by located and displayed for <RootNS>.ViewModels.PeopleViewModel.
For multiple views over the same viewmodel, the convention is that views of format <EntityName>.<Context> are displayed for viewmodels of format <EntityName>[<ViewSuffix>]ViewModel:
From your example, you could create a new folder named People, and inside it, create your views named Grid and List.
Your namespaces become <RootNS>.Views.People.Grid and <RootNS>.Views.People.List and, should then be located and displayed for <RootNS>.ViewModels.PeopleViewModel.
You typically then display the Views in something like a ContentControl, choosing the View you want to display by setting the cal:View.Context property. You'll either hard code the name, if the context isn't going to change in that particular control, or bind to a property which describes what state the ViewModel should be displayed as.
e.g.
<ContentControl cal:View.Model="{Binding Path=ActiveItem}"
cal:View.Context="List" />
See the Multiple Views over the Same ViewModel section.

As far as I can tell from the documentation you are referring to, you should not use View in your view name. Name your view classes People.Grid and People.List instead.

Related

How to make some elements of mainWindow common in other views?

I've got standard MainWindow.xaml. Then I added some pages which I wanted to show in the MainWindow. There are some common elements for all views, for example, header text, header image, and the name of logged user. How can I set these elements on the MainWindow that will be visible when another view is shown?
Set the appropriate items in the resources.
Properties that need these values will be able to get them using DynamicResource.
But it will be much better if you implement the Solution in the MVVM pattern.
Then you won't even have such a task (to transfer data between views).

other View(s) dependency?

I have view like the image and ViewModel have commands to handle the button (1,2,3,4) clicks. In work area allow the user to give inputs. Depending upon the input users are allowed click the button;
Each Button leads one new Window(View with ViewModel; whose model will be taken from the inputs). The new window have its own logic to showing the data depending upon the model injected to the ViewModel.
As per the MVVM standards, where do I specify the respective View and ViewModels for the each Button? (In View / View model).
How can I specify the same?
Basically ViewModel is a link between View and Model, so each combination of View and Model should have a separate ViewModel (if valid).
In my experience in most cases we are dealing with two kinds of Views:
small views such as icons, advanced buttons and so on (which are more isolated and more likely to have no reference to their parents so they are easy to manage and to be generalized)
large views such as windows, panels (which have a lot of children and are more likely to be changed later)
For small views common ViewModels can be used for multiple Views. but as for large Views (considering possible changes in the future) it's better not to use a single shared ViewModel. however it's helpful to use a base ViewModel class to implement some shared functionality (if any).
So keeping that in mind and focusing to stay standard, I suggest:
ViewModels for secondary windows: (according to the question I think you need 4) Each have their independent functionality (you can derive them all from a BaseWindowVm).best practice here would be not to let them know about their parent (MainWindowVm) and just to set their event handlers when they are instantiated. This way you can avoid code coupling.
MainWindowVm: consists of 4 commands and some other inputs. Each command does these steps:
instantiates a View
instantiates a ViewModel for secondary window based on input
set Vm's event handlers
assign the Vm to DataContext of the View
add the Vm to some list in MainWindowVm (If you want to keep track of these windows)
ShowDialog()
The most important part is that since ViewModels communicate with each other, linking Views with each other only make it more complicated and more difficult to manage. so Views are like islands with bindings to their ViewModels and everything else is up to ViewModels.

Split view into two separate views

I'm building a WPF application which very simplified looks something like this:
I have an ApplicationView which holds the menu and a ContentControl.
The ContentControl binds to the property CurrentViewModel which is set by the menu and rendered by its related View (Views and ViewModels are coupled by DataTemplates defined in the App.xaml).
I found this approach on Rachel Lim's blog
So in this example my View contains a list of duties as well as a "Details" window of the currently selected duty.
This setup works fine, but I think my ViewModels are getting too fat!
The non-simplified version of this ViewModel is up at around 500 lines of code, for handling:
Initializing filters
Logic for filtering list
Displaying duty details
Add/Update/Cancel/Delete logic
Now I'm very new to WPF but that seems like too much code, yea?
And it will be even bigger before I'm finished with it.
Anyways, I was thinking that I could split the ViewModel into two separate ViewModels; one for holding list and filters and one for showing the details. But how is this best accomplished?
I have thought of two approaches, but don't know which is preferable:
Create a DutyMasterView whose sole purpose is to hold two ContentControls for the actual Views (ie DutyListView and DutyDetailView each with their own ViewModel)?
I'm using MVVM Light as my framework so I suppose I could use the messaging service to tell the DutyDetailViewModel which Duty to display, right?
Alternately create a DutyMasterViewModel which exposes the selected duty.
Ditch the DutyMasterView and nest the DutyDetailView in the DutyListView.
Does it make sense to split my ViewModel into two or should I just stick with my fat ViewModel?
If splitting the ViewModel is recommended which of my suggestions makes most sense?
Are there other approaches that I should consider?
If you're still looking for opinion, I'd do it almost like you mentioned in point 1 but you don't need any messaging.
You create two VMs. Let's say DutiesVM and DutyDetailVM. DutyDetailsVM contains just some string properties for ID and Name.
In DutiesVM you create two properties:
ObservableCollection<DutyDetailVM> DutiesList
DutyDetailVM SelectedDuty
Your DutiesView can look like this:
<DockPanel>
<v:DutyDetailV DockPanel.Dock="Right" DataContext="{Binding SelectedDuty}">
<ListBox ItemsSource="{Binding DutiesList}" SelectedItem="{Binding SelectedDuty}"/>
</DockPanel>
Now you can create ListView ItemTemplate that binds to DutyDetailVM Properties.
is usercontrol that defines the DutyDetail view. Selecting the item in the list updates the details control automatically.
That's just the sketch but I think you can get the point from it.

Should I dependency inject? How do I do it?

Okay, so I am working with Microsoft Prism in WPF using a MVVMC(or MVCVM) pattern.
In my ChatModule I have a series of Views, ViewModels, and one Controller.
For the Views I have
ChatAreaView - Displays the chat messages that come in to be read. This is hosted inside of a TabControl region so that I can have chat windows between the user and other users, or maybe file transfer windows, etc.
UserAreaView - This is a list of the users. Right clicking has context menu to interact with them... like sending a file or whispering.
MessageAreaView - This is where the user types in messages to be sent to all of the others.
For each view, I have a corresponding ViewModel. ChatAreaViewModel, UserAreaViewModel and MessageAreaViewModel. These ViewModels essentially only contain properties.
For example, the UserAreaViewModel defines a struct of type User which is essentially just a Name. Actually this is defined outside of the class, but still... it uses it. It has an ObservableCollection to store a list of all the Users who are currently connected. It also has ICommand properties defined to interact with the user. Right now I have SendFile, Whisper and Nudge... with intent on adding more in the future.
The Controller creates these views and ViewModels, and marriages them. It news them up, assigns the ViewModel as the corresponding View's DataContext, and sets all the initial properties of the ViewModel. Over the lifetime of the module, it will react to user interaction and execute DelegateCommands that it has assigned to each of the ViewModel's ICommand properties. These will further alter the state of the properties in a ViewModel.
I am using the actual types of Views and ViewModels, instead of interfaces, like such.
#region Views
ChatAreaView viewChatArea;
UserListView viewUserArea;
MessageView viewMessageArea;
LoginPromptView viewLoginPrompt;
#endregion
#region ViewModels
ChatAreaViewModel viewModelChatArea;
UserAreaViewModel viewModelUserArea;
MessageAreaViewModel viewModelMessageArea;
LoginPromptViewModel viewModelLoginPrompt;
#endregion
Would things be a lot more neat, less coupled if I defined interfaces for the Views and ViewModels, and operated on these interfaces within the controller instead of the concrete implementations? Could I then just register them with my Container in the Module class(which is essentially the root of each Module)?
What do I have to gain from doing this? How would I implement an interface for each view to distinguish them from the others? They don't really do ANYTHING except have XAML... and teh ViewModel's don't really do anything either except have certain properties. And those properties might be subject to change. On the UserAreaViewModel for instance, I will definitely want to add more commands so a user can interact with another user in different ways.
Can somebody help me out here? In my mind I'm thinking I should be abstracting this stuff, but I don't really know a logical way I should be going about it, or even if it's a wise idea to do so. What do I have to gain?
Thank you for your time. The below image is an example of what I'm working on. Ignore the Add new Item button and the styling of everything... that's not what I'm working on right now.
loosely coupled - can replace an entire class with altogether different implementation in future.
independent development.. can inject a dummy UI / view until final UI gets ready. two pieces can evolve at the same time (after having a common contract).
no need to add references to the modules (implementing the view). can use ConfigurationModuleCatalog to discover types from config file.

MVVM - What's the correct track regarding Nested Lists and View Models?

Here's the thing:
I have a GetHistoryLog View, its view-model, and its model.
I have a listbox which points to a ObservableCollection<ChangesetEntity>
I have another view specialized on getting versioned items, so it's a VersionedItemView, its view-model, and its model.
Now I want GetHistoryLog View to access specific versioned items within its changesets. Each changeset can have multiple versioned items. What is the best way to "connect" the two view-models?
Here's what I want to do, a Tree-view containing all the changesets and child files, and a single list view containing all the changesets, with an option to click the changeset and view the modified files.
Basically, access a list of items inside a list of items, and at the same time have the option to access a specific index inside this list.
Do I need to create another view-model? What is the best solution without creating havoc in the code?
I hope I was clear enough
Thanks in adv.!
EDIT: Also, is there a way to set the DataContext of a control to some specific item in a list, dynamically?
EDIT: Trying to explain more clearly:
HistoryLogEntryModel -> GetHistoryLogVM -> GetHistoryLogUserControl
VersionedItemLogModel -> GetVersionedItemsLogVM -> GetVersionedItemsLogUserControl
What I want is:
HistoryLogEntryModel + VersionedItemLogModel -> ? -> GetCompleteHistoryLogWithVersionedItemsUserControl
(shorter name, but just for understanding)
Based on your description, I don't think you need anything more. You already have a very hierarchical object graph of your domain which will support the parent child relationships you're describing already.
I think you just need to polish up on your approach to binding and object presentation. Here is a good post from MSDN magazine that can help you with that and it also has advice for dealing with with Hierarchical Data Templates for use with a WPF TreeView.
If you want to do a binding that dynamically changes the DataContext of a control based on the SelectedItem of another control (ListBox for example), you can use the following binding syntax:
DataContext="{Binding ElementName=sourceElementNameHere, Path=SelectedItem,
Mode=OneWay}"
Here is another link to a good MSDN article on binding in WPF.

Resources