How to switch between ViewModels in multi-window WPF application? - c#

I am trying to create a WPF Model-View-ViewModel that has separate LoginWindow, RegistrationWindow and MainDashboardWindow.
I have already read Rachel Lim's solution on navigating with MVVM using ApplicationViewModel and ApplicationView that contains other views but I have trouble understanding something.
I was planning on using LoginViewModel and RegistrationViewmodel (none of them will inherit from BaseViewModel) by setting the DataContext of LoginWindow and RegistrationWindow and then after logging in to application start using a MainDashboardViewModel to switch between viewmodel's on MainDashboardWindow.
Is this the correct way to go?
If this is not the correct way to go, how can I implement an application-wide viewmodel that can be switched between windows (only one window will be opened at a time)?

To implement MVVM properly, you need to understand what is View, Model and ViewModel.
View is the UI that WON'T HAVE ANY CODE. The DataContext in View is the ViewModel class, one View should be associated with one ViewModel. You should set the DataContext by XAML code.
Model is the class contains the data and some methods to process for that data. I highly recommend you using Repository Pattern when design Model for you program.
ViewModel is where you put the business method in it. All ViewModel must implement from BaseViewModel and DON'T KNOW ANYTHING ABOUT VIEW.
In your case, you need to create 3 different Views, 3 ViewModels for 3 Views.
Let's start with your Login windows. First you need to specify what ViewModel for Login windows by indicate it on Login view.
<Window x:Class="SampleApplication.LoginWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SampleApplication.ViewModels"
Title="Login" Height="350" Width="525">
<Window.DataContext>
<local:LoginViewModel/>
</Window.DataContext>
You have 2 buttons in Login windows. one is Login and on is Register. Each button must be binded with an RelayCommand in ViewModel. By this way you can properly implement MVVM. To navigate between windows you must close you current windows and open a new one. To close windows, see this, to open windows, just create an object of your view and call ViewObject.Show();

Related

Which is the best way to show another window in wpf mvvm

Hi I got some problem with navigating windows in wpf mvvm. I got two wpf windows, let's say viewA and viewB. all respective view model are bind to the view using prism prism:ViewModelLocator.AutoWireViewModel="True" .
This is my view.
<Window x:Class="eBriefcase.WPF.Views.CaseHearing"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
Title="CaseHearing" Height="300" Width="300">
<Grid>
</Grid>
If I want to go to another view, I create new window and use show function in View Model.
ViewB vB_ = new ViewB();
vB_.Show();
when I press show another form button, another duplicate wpf window is open. How can I control it?
I just studied WPF for only 10 days. Is it the correct way of navigating between views?
Best Rgds,
df
The answer is in your question:
I create new window and use show function
So the new window is shown.
You are being confused with the term view. View is not some kind of object in WPF. It's just logical part of MVVM concepts.
Objects that you operate are Windows, controls and pages.
Looks like you want to use WPF pages as different views of your data.
There are plenty of manuals on the net about WPF pages and NavigationService
These are keywords that you need.
BTW, answering the question in the header: The best method to open windows is to wrap opening windows into some generic WindowManager and use
new WindowType(){ DataContext = VM }.Show()

MVVM Light & WPF - Binding Multiple instances of a Window to a ViewModel

I am working on my first project in MVVM and I've chosen to use the MVVM Light Toolkit. I have a GameViewModel that handles business on the main screen of my game. I need to find out how to open a new window (AdventurerView) with an instance of Adventurer as a parameter when a command is executed, have it bound to AdventurerViewModel, and display and return data. Instances of this window will be opened and closed frequently. I have been stuck on this for a couple of days now and it's driving me crazy. I would like to learn how to do this in an MVVM-friendly way, preferably with the tools provided by MVVM Light or pure XAML.
I've tried using MVVM Light's ViewModelLocator but since AdventurerView is a window it won't work; it says "Can't put a Window in a Style", though the program still compiles and runs. Could there be something I could change to make that work? Or is there another way to bind them in XAML? Or another approach entirely? I would really love to be able to move on from this. I have also tried using MVVM Light's messenger to no avail (which still doesn't tackle the View/ViewModel issue).
I just need to be able to create a window that is bound to AdventurerViewModel and display/return the appropriate data.
AdventurerView.xaml is in its default state at the moment, but I feel that if I could bind the appropriate data that might help (DataContext).
AdventurerViewModel is pretty bare-bones as well
class AdventurerViewModel : ViewModelBase
{
#region Members
private Adventurer _adv;
#endregion
#region Properties
public Adventurer Adv
{
get { return _adv; }
set { _adv = value; }
}
#endregion
#region Construction
public AdventurerViewModel(Adventurer adv)
{
this._adv = adv;
}
#endregion
}
App.xaml with the non-working DataTemplate at the bottom:
<Application StartupUri="MainWindow.xaml"
xmlns:views="clr-namespace:AoW.Views"
xmlns:vm="clr-namespace:AoW.ViewModels"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="AoW.App"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Application.Resources>
<vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />
<DataTemplate DataType="{x:Type vm:GameViewModel}">
<views:GameView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:TitleViewModel}">
<views:TitleView />
</DataTemplate>
<DataTemplate DataType="{x:Type vm:AdventurerViewModel}">
<views:AdventurerView />
</DataTemplate>
</Application.Resources>
</Application>
The command in GameViewModel that will hopefully make this all happen (the messagebox just confirms that the command is firing):
private void ExecuteShowAdvCommand(Adventurer adv)
{
System.Windows.MessageBox.Show(adv.Name);
}
I don't really know what else to include.
Ok I put together a demo that should make this hopefully easier for you Download Link
Functionality:
3 Windows in Total (MainWindow, ModalWindow, NonModalWindow)
MainWindow has a TextBox you can type whatever you want into.
2 buttons on the top will open the Modal / NonModal Window accordingly
Each window when opened will display the message that was in MainWindow's TextBox in a TextBlock inside them.
In each window you can tick a CheckBox to update the value in result's textblock in MainWindow (For the Modal Window this will kick in when modal window is closed. For NonModal changes can be seen asap)
That's it for functionality,
Concepts:
Registering Multiple VM's with the SimpleIoC and using GetInstance(...) to request them out.
Messenger class usage with a custom message type OpenWindowMessage
Opening Modal / Non Modal Windows from a parent VM staying true to the MVVM principles
Passing data between windows(just shown in NonModal)
Important Note:
- The method used in this example to set the non DP DialogResult from the modal window is not MVVM friendly cos it uses code-behind to set the DialogResult property on a Window.Closing event which should be avoided(If needing to be "testable"). My preferred approach is a bit long and is very well documented HERE(Mixture of question and answer). Hence why I ignored it for the sake of this sample.
Follow up to Viv, I modified the sample to include an example of opening the window without using a code behind.
Sample project is here.
I'm utilizing the ViewModelLocator singleton with a static method that news up the viewmodel and window and Data Context instead of the code behind.
Blog Post with Details.
Let me know which method is preferable. I dislike using code behind, but there could be pro's and con's I'm missing.

MVVM and View/ViewModel hierarchy

I'm working on making my first game using C# and XAML for Windows 8. I'm still learning the core concepts and best practices, and MVVM has been a hurdle. I'll attempt to ask the question in two parts.
Background
The game I'm making is Sudoku. Sudoku has a board that contains a 9x9 grid of tiles. I have three models - Game, Board, and Tile. When a Game is created, it automatically creates a Board, and when the Board is created, it creates 81 (9x9) Tiles.
1. With a hierarchy of views, how are corresponding view models created?
To match the hierarchy of models, I would like to have a hierarchy of views (GameView contains a BoardView which contains 81 TileViews). In XAML, it's pretty easy to create this hierarchy of views with user controls, but I don't understand how the view models get created.
In the examples I've seen, the data context of a user control is often set to the view model (using the ViewModelLocator as a source) which creates a fresh instance of the view model. This seems to work well if you have a flat view, but also seems like it gets messy when you have a hierarchy. Does the GameView create a GameViewModel and leave it up to its BoardView child to create a BoardViewModel? If so, how does the GameViewModel communicate with the BoardViewModel? Can the BoardViewModel communicate back up the hierarchy to the GameViewModel?
2. How does a view model get model data?
In iOS, I would start by using a service to fetch a Game model that was pre-populated with data. I would then create a GameViewController view controller (which was in charge of creating the view) and pass the Game to it. In MVVM, I see the value in having a view be in charge of creating its own view model (ideally using a ViewModelLocator), but I don't understand how that view model gets the model.
In all of the examples I've found online, the view model uses some service to fetch its own data. But I haven't come across any example that accepts constructor params or params passed from a higher level of navigation. How is this done?
I don't want to use an application resource or some other kind of singleton storage method for my model because, not that I do, but what if I wanted to display multiple puzzles on the screen at once? Each GameView should contain its own Game.
Not only does the GameViewModel need a reference to the Game model, but the BoardViewModel that was created somehow (see question 1) needs a reference to the Board model that belongs to the Game model. The same goes for all the Tiles. How is all this information passed down the chain? Can I do this much heavy lifting entirely within XAML, or am I going to have to do some sort of binding or other initialization in code?
Phew!
I appreciate any advice you can give, even if it's not a full answer. I'm also keen to find any examples of MVVM projects that share similar challenges to my own. Thanks a ton!
I would start by creating a class to begin the application with. Typically I call that class something like ApplicationViewModel or ShellViewModel, even though technically it can abide by different rules than what I would typically use for a ViewModel
This class gets instantiated at startup, and is the DataContext for the ShellView or ApplicationView
// App.xaml.cs
private void OnStartup(object sender, StartupEventArgs e)
{
var shellVM = new ShellViewModel();
var shellView = new ShellView();
shellView.DataContext = shellVM;
shellView.Show();
}
This is usually the only place I set a DataContext for a UI component directly. From this point on, your ViewModels are the application. Its important to keep this in mind when working with MVVM. Your Views are simply a user friendly interface that allows users to interact with the ViewModels. They're not actually considered part of the application code.
For example, your ShellViewModel may contain:
BoardViewModel CurrentBoard
UserViewModel CurrentUser
ICommand NewGameCommand
ICommand ExitCommand
and your ShellView might contain something like this:
<DockPanel>
<Button Command="{Binding NewGameCommand}"
Content="New Game" DockPanel.Dock="Top" />
<ContentControl Content="{Binding CurrentBoard}" />
</DockPanel>
This will actually render your BoardViewModel object into the UI as the ContentControl.Content. To specify how to draw your BoardViewModel, you can either specify a DataTemplate in ContentControl.ContentTemplate, or use implicit DataTemplates.
An implicit DataTemplate is simply a DataTemplate for a class that doesn't have an x:Key associated with it. WPF will use this template anytime it encounters an object of the specified class in the UI.
So using
<Window.Resources>
<DataTemplate DataType="{x:Type local:BoardViewModel}">
<local:BoardView />
</DataTemplate>
</Window.Resources>
will mean that instead of drawing
<ContentControl>
BoardViewModel
</ContentControl>
it will draw
<ContentControl>
<local:BoardView />
</ContentControl>
Now the BoardView could contain something like
<ItemsControl ItemsSource="{Binding Squares}">
<ItemsControl.ItemTemplate>
<ItemsPanelTemplate>
<UniformGrid Rows="3" Columns="3" />
</ItemsPanelTemplate>
<ItemsControl.ItemTemplate>
</ItemsControl>
and it would draw a board using a 3x3 UniformGrid, with each cell containing the contents of your Squares array. If your BoardViewModel.Squares property happened to be an array of TileModel objects, then each grid cell would contain a TileModel, and you could again use an implicit DataTemplate to tell WPF how to draw each TileModel
Now as for how your ViewModel gets its actual data objects, that's up to you. I prefer to abstract all data access behind a class such as a Repository, and have my ViewModel simply call something like SodokuRepository.GetSavedGame(gameId);. It makes the application easy to test and maintain.
However you get your data, keep in mind that the ViewModel and Models are your application, so they should be responsible for getting data. Don't do that in the View. Personally I like keeping my Model layer for plain objects that hold data only, so only ever perform data access operations from my ViewModels.
For communication between ViewModels, I actually have an article on my blog about that. To summarize, use a messaging system such as Microsoft Prism's EventAggregator or MVVM Light's Messenger. They work like a kind of paging system: any class can subscribe to receive messages of a specific type, and any class can broadcast messages.
For example, your ShellViewModel might subscribe to receive ExitProgram messages and close the application when it hears one, and you can broadcast an ExitProgram message from anywhere in your application.
I suppose another method would be to just attach handlers from one class to another, such as calling CurrentBoardViewModel.ExitCommand += Exit; from the ShellViewModel, but I find that messy and prefer using a messaging system.
Anyways, I hope that answers some of your questions and will point you in the right direction. Goodluck with your project :)

MVVM Light - Multiple ViewModels (and connecting them up)

I am trying to learn the MVVM pattern (C#), having come from a Windows Forms background. I am using the MVVM Light toolkit, and so far I think it is brilliant.
I have made several small applications, however one thing I am struggling with is introducing a second view.
I want to (for example), have a button on my MainViewModel, which via a RelayCommand, opens up a new Window - let's say an "About" window. I have done hours of research on the web for this however it seems I can't get my AboutViewModel to communicate with/show my AboutView.
I have placed a receiving messenger in the code-behind constructor of the AboutView.xaml - however I can't get it to receive any messages from the AboutViewModel, and thus can't make it 'Show()'.
If anyone has an example of an Mvvm Light WPF app using multiple views that would be great :)
There are two ways I can think to do this easily
The first would be to use a Popup instead of a new Window. For example, I often put properties in my ViewModel for PopupContent and IsPopupVisible, and set those values anytime I want to display my Popup control. For example, a ShowAboutPopup relay command might run something like this:
void ShowAboutPopup()
{
PopupContent = new AboutViewModel();
IsPopupVisible = true;
}
You can display it using a Popup object, or a custom UserControl. I prefer to use my own custom Popup UserControl, which will usually end up looking like this:
<Window>
<Canvas x:Name="RootPanel">
<SomePanel>
<!-- Regular content goes here -->
</SomePanel>
<local:PopupPanel Content="{Binding PopupContent}"
local:PopupPanel.IsPopupVisible="{Binding IsPopupVisible}"
local:PopupPanel.PopupParent="{Binding ElementName=RootPanel}" />
</Canvas>
</Window>
The PopupContent property is a ViewModel (such as an AboutViewModel), and DataTemplates are used to tell WPF to draw specific ViewModels with specific Views
<Window.Resources>
<DataTemplate DataType="{x:Type local:AboutViewModel}">
<local:AboutView />
</DataTemplate>
</Window.Resources>
The other method is to have some kind of ApplicationViewModel that runs on startup, and is responsible for the overall application state, which includes which window(s) are open.
Typically I prefer to have a single ApplicationView that contains a ContentControl to display the current page
<Window>
<ContentControl Content="{Binding CurrentViewModel}" />
</Window>
however it can also be used to manage multiple windows. If you do use it to manage multiple Window objects, be warned that this will not be a pure ViewModel because it will need to access some View-specific objects, and referencing UI objects it not something a ViewModel should do. For example, it may subscribe to receive ShowWindow messages, and upon receiving those messages it would create the specified View and show it, and possibly hide the current window as well.
Personally, I try to avoid multiple windows as much as possible. My usual method is to have a single View that contains consistent application objects for any page, and a ContentControl containing dynamic content that changes. I have an example using this navigation style on my blog if you're interested
As i can see you want a navigation in your MVVM app?
Word goes to the creator of MVVM Light - Laurent Bugnion - with his post about using Navigation Service for switching Views. It's actually about Windows Phone & Silverlight but same should apply to WPF.
Also this answer in related question uses this approach.

MVVM ViewModel to View Communication

I am new to MVVM and working on an application, i want to achieve few things in my application
My viewmodel should be able to initiate a new view.
scenario(a command is bind to a button and some process decide what to do and based on the result, i need to show View1 or View2)
Upon a successfull operation my viewmodel should display a messagebox, if multiple views are open then message must prompt upon the right view(with which viewmodel is bind).
I want to provide some kind of notification from my view model to view. Kindly guide me in the right direction.
Thanks
You might want to try out some of the many mvvm frameworks out there. I personally like mvvm light because it works in silverlight and WPF, and it's easy to use http://mvvmlight.codeplex.com/ (no affiliation)
Here is a nice compare/contrast of some of the major frameworks: What framework for MVVM should I use?
Most of the frameworks have a messaging system that provides the ability to send updates between the view and the viewmodel as well as between viewmodels. Most of the frameworks also provide canned messages that handle MVVM messageboxs as well (I know MVVM Light does).
To handle switching between views in WPF I use DataTemplates and Content controls
In the view .xaml I add
<ContentControl Content="{Binding ActiveViewModel}" />
and this is the space where the injected view will be displayed. The ActiveViewModel is the object for the viewModel that holds the selected viewModel.
In a ResourceDictionary I add something like:
<DataTemplate DataType="{x:Type ViewModelNameSpace:ViewModelClassName}">
<ViewNameSpace:ViewClasName/>
</DataTemplate>
Finally in the ViewModel I set the ActiveViewModel property (that is setup to notify the UI of changes via INotifyPropertyChanged) to an instance of the viewModel I would like to use.
ActiveViewModel = new ViewModelClass();
You should create a new View and Navigate to it.
You can use messaging in MVVM Light framework. Send message from your ViewModel to View. Examples:
http://chriskoenig.net/2010/07/05/mvvm-light-messaging/

Categories