Reputation: 961
I'm building a WPF-based Point-of-sales system to practice using MVVM.
I did not use any MVVM framework, instead used the RelayCommand
class in the article by Josh Smith
http://msdn.microsoft.com/en-us/magazine/dd419663.aspx#id0090030
I previously had written one, without applying the MVVM pattern (still using WPF).
For database access I used Entity Framework. It looks like this:
My question is, how do I achieve this using MVVM?
Firstly, I already wrote the Login
window using MVVM, and my immediate questions are,
Login
window (dispose it) and open the MainWindow
?MainWindow
contains only the top section of the screenshot, which is the row of buttons.View
and ViewModel
, using the MainWindow
only as a place to put everything together? If so, how do I code that when the button is clicked, the "button bar"'s ViewModel
would tell the MainWindow
's ViewModel
to load the respective View
s (I used System.Windows.Controls.Page
in the non-MVVM version) into the Frame
? In the non-MVVM version, the code I used is fairly simple:
private void btnCheckout_Click(object sender, RoutedEventArgs e) {
mainFrame.Navigated += frame_Navigated;
var pgCheckout = new pgCheckout();
mainFrame.Navigate(pgCheckout); //The frame
}
If not, how do I load another Page
into the Frame
?
Upvotes: 2
Views: 1870
Reputation: 50672
A way of solving these issues is by creating a single object that is responsible for loading and unloading Views.
At the start of the application an instance is created of this object and the object will show a Window (that will display all Views), create an instance of a ViewModel and a View, set the DataContext of the View to the ViewModel and pass the View to the Window so it can be displayed (e.g., set as a child of a Grid)
To close a View and/or open another View: when a Command of the current ViewModel is executed a message could be send to the the same object. The object can signal the Window to close the current View and can open a new one in same manner the first View was opened. The command can even pass a parameter that indicated the ViewModel that has to be loaded.
To send the messages I recommend a MessageBroker that uses weak events to pass messages. If you do not use weak events the application is at risk of hogging memory because the event handlers keep the garbage collection from cleaning up. See MVVM Light for such a Messenger
Regarding your questions:
Follow the steps above.
and 3. Whether or not to split ViewModels and Views is a matter of reuse and decomposition as in any other application.
and 5. Do NOT code click-events. Execute commands passing the desired View, ViewModel and possibly the container (ContentControl?) that will host the View.
Upvotes: 1
Reputation: 6445
If you don't use any existing framework, you will have to create one yourself. IMO you can benefit from that because you are in control of everything, but also you have to reinvent lot of things. I can describe how we do it, whether it's right or wrong let the votes here decide :)
First thing you don't want to pollute ViewModel code with any UI related objects. But, ViewModel is about view logic and you need to somehow control the presentation (navigation, user messages...). So you can introduce some sort of view service into your view model that controls view related logic, but does not depend on anything from the UI framework. Let's say something like:
public interface IViewService
{
//show message dialog with message text
void ShowMessageDialog(string message);
//show Yes/No message dialog with message text. Retrun true if answer is Yes
bool AskQuestion(string message);
//Navigate to some other viewmodel
void NavigateTo(ViewModel someOtherViewModel);
}
and you have to create concrete implementation of such service with WPF related logic. How that methods are implemented is up to you and the UI framework you are using (WPF in this case).
In your viewmodels you need to somehow get the object that implements IViewService
. You can inject it by using dependency injection, get the instance with service locator or even have some hard coded static singleton instance. (IMO dependency injection is the way to go, but also complicates things further, you need to introduce DI container and create all viewmodel instances using DI container).
Inside your commands then you can call methods of the service.
Let’s say your LoginCommand of your LoginViewModel (RelayCommand
that the Login Button binds to)
private void ExecuteLoginCommand(object parameter)
{
bool loginOk = Login(.....);
if(loginOk)
viewService.NavigateTo(new MainWindowViewModel);
else
viewService.ShowMessage("Login failed");
}
Most important thing, ViewModel is in control of presentation related logic, but does not know anything about UI framework behind. All of the "WPF" code is in the class that implements IViewService. In your viewmodels you "program to interface" so you are not tightly coupled with WPF logic, your ViewModels are "testable" and you could even reuse same viewmodel code on some other UI platform.
Upvotes: 1