Page Specific Navigation in WPF MVVM - c#

How do I implement page specific navigation in WPF using MVVM? For example, if I have a "Settings" page and an "Accounts" page, each page has their own unique page specific navigation, but each navigation items are located in the same container in the app. The navigation container is docked to the left hand side of the app window, and will never change, the navigation items however change depending on the page the user is on. I have two approaches:
Create a navigation view and view model for each different navigation for each page
Create one navigation view and view model and dynamically add the necessary buttons accordingly based on whatever page the user is on
The second options seems better in my opinion, as it is more dynamic and only uses one view/view model, however I am not sure how to implement this. I can easily code up a view and view model for one navigation container, but making it dynamic is a little trickier. Any ideas?
Thanks!

I think you want to use DataTemplate and ContentControl, see Jeremy Alles Blog for a good example
So to answer your question, I would create a view and view model for each.

Use NavigationService and create the appropriate views and viewmodels.

Related

WPF A list of non-homogeneous views

I have a WPF application that I want to present a list of non-homogeneous VIEWS. I want to have a button that I can write a handler for that would display a view. Then since it is a view the user could interact with it (enter values in a TextBox for example) using an underlying view model (MVVM). So let me explain further. The flow that I am looking to achieve is that a user selects which view to display. The view is displayed in a list. Then the user interacts with this instance of the view. When the user clicks on the button again a possibly different view is displayed and the user can now interact with two views. This continues as long as the 'add' button is clicked adding to the views in the list. This is further complicated because first, each of these views first are different. The particular view that should be displayed is dependent on a parameter that is passed to the command. Second it is complicated because each of these views also have dependencies that are passed in via IoC and on down to the associated view model. In other words there is not a parameterless constructor for the view models. So I cannot define a view model/view relationship like:
<Window.Resources>
<DataTemplate DataType="{x:Type views:SelectCustomerViewModel}"\>
<views:SelectCustomerView/>
</DataTemplate>
</Window.Resources>
I have searched and I see that one solution that comes close using the ItemTemplateSelector as outlined here. But as far as I can tell this only is a solution for a non-homogeneous display. If I revert to a list of views then it seems like I am breaking the MVVM model, as I would have to construct an appropriate view and assign the appropriate view model. How should I display/bring up a dynamic list of different views using the IoC from App.Xaml.cs?
An ItemTemplateSelector is a perfectly valid way of showing a different view (or portion of a view) for (possibly disparate) items that are shown in a list. Under the hood this is an implementation of a strategy pattern, where the view is chosen based on the data item.
However it seems that a tab view would also fit your criteria - as the command is triggered you instantiate a new tab for the required view. This view can be bound to the same viewmodel, so you could have changes from one tab being echoed on another tab. IIRC there are some tab view implementations that include something similar to a ItemTemplateSelector (because a tab view is a variation on a list control).
As for the IoC - don't be concerned about complexities there. Most IoC implementations will allow you to specify constructor parameter values or expressions as part of registering types.

Understanding of how to use "Container View" in iOS Designer

One can add a Container View on an existing view with the help of iOS Designer. A container view is placed on the existing view with an embed segue to a new added view controller. The new added view controller is responsible for the content of the container view.
One problem is that you can't change the embed segue or create a new embed segue. The only way is described here. But how do you use that? I saw an example by exchanging the view controller in the container. That's not what I want. I want to display multiple view controllers in one container, but I only get this managed by code.
So for what use cases is this Container View element?
"Container View" is a bit of a misnomer in this case. It doesn't actually contain anything.
What it does is place a frame onto the "parent" view controller's view to show you where the contained view will appear.
By doing this you can then use constraints on it and design around it etc...
If you want multiple separate view controllers to be contained in a parent view controller then you can always just add additional container views and set them up with new container segues.
But I think there might be a better way to achieve what you want to do.
Update
OK, from what it sounds like you want to have Table 1 on the screen. Then the user selects something and then table 2 is shown. Then Table 3. etc...
To do this I would do the following...
Make your "container segue" point to a navigation controller. Not to a table.
Then the root view of your navigation controller will be table 1. Then you can use normal "push" segues to go to table 2 and table 3. You can even put these into the designer and use segues.
So like this...
[] = view controller
() = segue
[Parent]-(embed)-[Navigation Controller]-(root)-[Table1]-(push)-[Table2]-(push)-[Table3]
That should do what you want.

Dynamically Adding Different Views Using MVP

First off let me say this is my first attempt into trying MVP. I am going for the Passive View approach as I want to completely decouple the Views from the Model.
I have read up on MVP by reading the following articles among others
Derek Greer
http://aspiringcraftsman.com/2007/08/25/interactive-application-architecture/
Todd Snyder
http://blogs.infragistics.com/blogs/todd_snyder/archive/2007/10/17/mvc-or-mvp-pattern-whats-the-difference.aspx
My application is going to have 4 Views that are custom controls in which each implement a different interface to interact with the Presenter. Now this is not a problem for 3 of the views as the controls are static and never change.
My problem comes along where on the 4th View I need to change the control/View that is displayed based on events triggered from View 1.
So for example lets say View 1 is a list of people who can be from either an employee or a customer. Now depending on who is selected you can modify different parameters depending on the type of person selected. The problem is that View 4 needs to dynamically change the editing control based on what is selected. Keep in mind not only the properties will be different but how they are edited as well. Also each editing control is going to fire different events for property changes.
So how does my Presenter know how to manage interaction with the Model, when depending on whether an employee or customer is selected there is a different editor that implements a different View interface?
I hope that was clear. Any help is greatly appreciated. I have searched all over and all examples show a concrete relationship between the View and Presenter whereas mine needs to be extremely flexible.
My goal here is to keep the editing controls on the 4th View so flexible that I could for example add editing controls/Views for aliens or dogs or whatever else I might add to View1 to be selected.
Thanks
You can create a top-level presenter that listens for selection events and changes the editing control by instantiating different MVP triads based on what is selected. Typically in MVP your presenters manage all the construction/dependencies.
I personally don't like having a 'Master Presenter' per se. I do build composite presenters: e.g. View can contain one of several views, so I build a Presenter for the master view, which sends commands (messages, events, whatever) to a specific child presenter (I don't expose any View outside it's owning Presenter).
Don't over-complicate things ...use a different View for each responsibility. Views are cheap.

Using Commands declared in "Parent" ViewModel (MVVM)

(Note: I chose to not use the Navigation Framework)
I have a WizardViewModel which is linked to WizardView.
The WizardViewModel declares and instantiates a command "Next".
It also contains a Property "ActiveSpell" of Type SpellViewModel.
The SpellViewModel contains several PageViewModels, each having a View counterpart.
The ActivePage Property (on SpellViewModel) tells the ui which view to take.
Now I have the following problem:
When I click a button to switch to the next page,
I need access to the "Next" command defined in the WizardViewModel,
but I only have access to a PageViewModel there.
I could just add a Parent property to each child ViewModel,
but I'm not sure if that is a good idea.
Or maybe there is another nicer/common way to do that.
You can use Event Aggregator, to adjust the interaction between ViewModels.
You don't need Parent property. Your view model structure is good, just look at the picture, to understand how you should bind your view model onto the view:
Next command should be implemented something like that:
public void NextExecute()
{
ActualSpell.MoveToNextPage();
}
UPDATE:
According to your comment, Arokh, I've updated the post.
I think, in this case you should implement ActivateCreatePersonSpell command in WizardViewModel.This command should:
save actual spell state
open CreatePerson spell
once person is created set saved spell with result of creation person
The last what you need to do is to bind ActivateCreatePersonSpell command to button on the page. I propose to use ViewModelLocator for these purposes.Look at this post for example.
I had to implement a wizard once and I liked and mimicked the way Josh Smith and Karl Shifflett set up their WizardViewModel and wizard page view models in this example project (source code available with the article):
http://www.codeproject.com/KB/WPF/InternationalizedWizard.aspx
They kept the Next command as part of their WizardViewModel, but created a WizardPageViewModelBase that all of the wizard pages derive from. That allowed the WizardViewModel to control which page is the current page, and it allowed the WizardViewModel to query the current page view model to see if the Next command can execute, thus enabling or disabling the Next button on the wizard. (That is, the wizard view model knew about the page view models, but the page view models didn't need to know anything about the "parent" wizard view model.)
As for adding links to parent view models, it's an approach that works, and I've done it before when I started working with MVVM, but after time I found the approach to result in some difficult to maintain code as every view model becomes interdependent.

Reusing a menu with mvvm and wpf

I was wondering what the best approach is for sharing a menu across all wpf windows/views.
My Application doesnt really fit the navigation model, so will probably use a Ribbon control.
I am leaning towards creating a user control for the menu and dropping it on each view, but have also seen Josh Smith's msdn article, where he loads user controls.
Are there any other options or established best practices?
Thanks in Advance.
I ended up implementing in a way similar to Josh Smiths; I have however simplified things a bit.
All views are usercontrols, except the MainWindow.
The MainWindow contains a ContentTemplate which is bound to a property holding reference to a single UserControl in the view model.
I then have an ApplicationController responsible for controlling the view and view model lifecycle.
The ViewModel base class used by each view contains a reference to the IApplicationController.
The MainWindowViewModel then makes calls to the ApplicationController to load a new view etc.
Still not 100% on this approach so would welcome any further suggestions.
Here's what I would probably try:
Define an ISharedMenu interface
Create a UserControl which uses the ISharedMenu as its DataContext.
For each ViewModel that you want to use the shared menu, implement the ISharedMenu interface.

Categories

Resources