Questions regarding appropriate use of ViewModelLocator in MVVM - c#

I am working on a WPF/MVVM app using MVVM Light. Right now my ViewModelLocator is pretty standard; it includes a static constructor that registers the ViewModels via SimpleIoc and has properties returning the current instances of the ViewModels.
I don't know how appropriate this is, but I have been exploring using instances of ViewModelLocator in ViewModels to access properties of other ViewModels and to change ContentControl in one of my views. If there are any major problems with doing that, please let me know so that I can find a way around it. For example, I may have something in a ViewModel like:
private ViewModelLocator _viewModelLocator = new ViewModelLocator();
private void SomeMethod()
{
_viewModelLocator.OtherViewModel.SomeProperty = something;
}
In a different ViewModel I have the following:
private ViewModelLocator _viewModelLocator = new ViewModelLocator();
public ViewModelBase CurrentViewModel { get; set; }
private void SomeMethod()
{
CurrentViewModel = _viewModelLocator.SomeViewModel;
}
In this case, CurrentViewModel is bound to a ContentControl in my view.
At the moment being able to do this is very convenient but I'd like to get some input from more experienced programmers to make sure that I'm not shooting myself in the foot. If there is a problem with it, are there more acceptable routes I can take to achieve the same results?
Now, if there is nothing wrong with the aforementioned approach, I would like to know if it would be appropriate and/or acceptable to make ViewModelLocator static. To try things out, I did a quick changeover to a static ViewModelLocator. In my MainWindow.xaml, I set the DataContext to:
DataContext="{Binding Source={x:Static vm:ViewModelLocator.Main}}"
...and going back to the first example, I can use:
private void SomeMethod()
{
ViewModelLocator.OtherViewModel.SomeProperty = something;
}
and:
public ViewModelBase CurrentViewModel { get; set; }
private void SomeMethod()
{
CurrentViewModel = ViewModelLocator.SomeViewModel;
}
Right now the program works fine using a static ViewModelLocator, but it is in its infancy, so I'd like to know if this is something that could be a viable option in the future or if I should stay away from a static ViewModelLocator altogether.
Any advice or input on these issues would be greatly appreciated. I am still fairly new to programming and I would like to learn techniques that will serve me well in the long run.
If there are no glaring issues with what I'm doing here, please let me know as well.
Thanks.

It is considered incorrect to reference other view models from view models. This breaks the decoupling that is supposed to make you project more testable and maintainable. If I need to have properties accessable from a number of view models I create a service like iUniversalAppDataService and then use the dependency injection built into MVVM-Light to resolve when the vewimodel is created.
ie this is the constructor of your viewmodel:
public New(IUniversalAppDataService AppDataService)
{
_MyAppDataService = AppDataService;
}
That way any changes/properties within that service are available to any viewmodel that implements the service.
the service needs to be declared in the viewmodellocator as well:
SimpleIoc.Default.Register<IUniversalAppDataService , UniversalAppDataService >
I have used this method to create navigation services that respond to user navigation and of course data services from databases or web data services. I strongly suggest using this service approach because it is WAY easier to maintain in the long run should there be changes to your underlying data model or app architecture.

Related

MVVM Handling Window Management using Factory Approach

I delegate creation(showing) of my Windows to my WindowFactory, that attaches a ViewModel to the View and shows the window. It is injected into my MainViewModel Constructor parameters.
The factory itself is very simple:
public class ProductionWindowFactory : IWindowFactory
{
public void CreateNewWindow()
{
PhoneWindow window = new PhoneWindow();
{
window.DataContext = new phoneWindowViewModel();
}
window.Show();
}
}
Now, I'm aiming at implementing more functionality of my new windows, that will happen on certain button clicks IN that new window.
As I am fairly new to Factories in general, I'm struggling to grasp a certain concept:
Example:
We have a ViewA that has a ViewModelA attached to it.
That view has a button with a command attached, that tells our WindowFactory to show a new ViewB.
ViewB has a ViewModelB and a close button, that tells it to close ViewB.
Now, since we shouldn't reference our ViewB in our ViewModelB, we have to somehow let it know which view it should close.
I have come up with possible ideas / solutions, but I would really
appreciate you letting me know which one follows the MVVM and Factory
pattern "the most", and which one is usually used in such situations.
Make our ViewModelB take an instance of windowFactory that created ViewB as a parameter on initialization, and build a method in the Factory that closes ViewB and is executed through button click -> command.
Create an IWindowManager? that inherits from IWindowFactory and build a WindowManager class, that extends the capabilities of our WindowFactory, and push it in ViewModel constructors as described above.
Any other correct solution, that I am completely unaware of?
Please bear in mind, that the above is just an example. Ideally, I'd like to implement more of advanced functionality to my windows, and have an ability to create & manage multiple different ones using that one factory.
I have not attached much code, since I'm still at the stage of learning and deciding which solution should I go with.
EDIT - REGARDING POSSIBLE DUPLICATE:
My question differs from the proposed duplicate, as the other one is simply about managing of closing windows - My question is about doing that as well, but following a FactoryPattern.
I have specified very clear guidelines in what I am trying to achieve and in what ways, that are completely different from the question linked.
First of all, the answer is none. The job of a factory is to create new objects, think of it as an elaborate new operator. Also, the idea of following a pattern "the most" is problematic in and of itself. You employ patterns because they help you achieve certain goals, e.g. you employ mvvm to evade coded-ui tests as much as possible, because they are fragile, normally.
That being said, what to do with its view is completely up to the view's view model.
Example: if one view model needs to close its own window, do it with a command as illustrated in the comment. If a view has a close all-button, its view model will have a dependency on some kind of window registry that can enumerate all open windows for the close all-command to close.
When looking at your view model, try to come up with an idea of what services it needs from the rest of the application, and inject those dependencies as interfaces. When implementing the interfaces, most likely there will be classes that implement more than one, e.g. WindowManager might implement IWindowFactory and IWindowRegistry thus making it very easy to put all newly created windows into the list of open windows. The window will have a dependency on the IWindowRegistry, too, most likely, to unregister itself when it gets closed.
The duplicate was not far off. Here is a simple adaptation of the scenario in OP
interface IView {
void Close();
}
class ViewAdapter : IView {
readonly Window view;
public ViewAdapter(Window view){
this.view = view;
}
public void Close() {
view.Close();
}
}
public class ProductionWindowFactory : IWindowFactory {
public void CreateNewWindow() {
var view = new PhoneWindow();
var viewAdapter = new ViewAdapter(view)
var viewModel = new phoneWindowViewModel(viewAdapter);
//Bind
view.DataContext = viewModel;
view.Show();
}
}
If the view model wants to instruct that the view be closed it can ask the injected contract to do so.

How to access to all viewmodels via the viewmodel base?

I've created a ViewModel class that have inside the implementation of INotifyPropertyChanged, now I also have other ViewModels that inherit from the ViewModel (base).
All working good actually but I have a doubt.
So let's say that I've in the CustomerViewModel an ObservableCollection called Price, like this:
private ObservableCollection<Models.Price> _price = new ObservableCollection<Models.Price>();
public ObservableCollection<Models.Price> Price
{
get { return _price; }
}
this ObservableCollection should be populated by other classes, 'cause I need to access to the same resource.
I really don't understand how can I do this in mvvm. I though to a Singleton ViewModel, so something like this defined in the base VM:
public static ViewModel Instance { get; set; }
So import all the childs VM into the base and access them via ViewModel.Instance.Price;
but doesn't seems a good practice for me. Any idea?
With this implementation, you can share the same Datasource to all ViewModels
public class PriceGenerator {
private PriceGenerator() {
this.Prices = new ObservableCollection<Price>();
this.Generate();
}
void Generate() {
//Generate Objects here
this.Prices.Add(generatedPrice);
}
public ObservableCollection<Price> Prices {
get;
}
private static PriceGenerator _instance;
public static PriceGenerator Instance => _instance ?? (_instance = new PriceGenerator());
}
There are generally two approaches to this.
Even if you don't have a real database/repository, implement a singleton class that simulates this. This singleton class should also implement INotifyPropertyChanged (and/or INotifyCollectionChanged as appropriate). All ViewModels will be able to access this simulated repository, and interested ViewModels can choose to subscribe to this repository's PropertyChanged callback. For your question, it is generally tidier to have a repository that handles just prices, rather than having a simulated repository that stores 101 different information.
Have a main ViewModel. Some people would visualize that the MainWindow being the main view, with a corresponding main ViewModel. This ViewModel is intentionally made a singleton, which other ViewModels can access through static call. This main ViewModel is basically acting just like #1 - it is like a repository that stores 101 different information. That main ViewModel is likely to look untidy, but it is simply to trace where things are stored - if you need any data, it's probably in there.
Personally, I prefer to use the first approach. lokusking's answer is an example of this approach. Although his "repository" does more than storing data.

Correct approach when notifying ViewModels of UserControl events in WPF MVVM?

In my WPF View, I'm loading data into User Controls like this:
<ContentControl Content="{Binding ItemEditVm}" />
And then in the ViewModel:
private ItemEditViewModel _itemEditVm;
public ItemEditViewModel ItemEditVm
{
get
{
return _itemEditVm;
}
set
{
_itemEditVm = value;
OnPropertyChanged("ItemEditVm");
}
}
I've got a series of DataTemplates to say which View belongs to which ViewModel. And then in my business logic, I can just spin up a new ViewModel for the UserControl then assign it to the property and all works as expected.
However, to resolve the next task in this application, I need to be able to notify the parent ViewModel of events occurring inside the UserControl. I've done this with a simple event on my child ViewModel and a listener on the parent:
public event EventHandler ItemEditViewModelChanged();
So when I create my ViewModel I can just add a listener:
ItemEditViewModel vm = new ItemEditViewModel(itemId);
vm.ItemEditViewModelChanged += vm_ItemEditViewModelChanged;
And do what needs to be done in vm_ItemEditViewModelChanged().
However, I am instinctively uncomfortable with this. While it doesn't violate any MVVM principles direclty (things are still testable, Views and ViewModels are still separate), it doesn't seem a very flexible way of doing things and it does create undesirable logical links between ViewModel classes.
Is there a better way of doing this? Is my approach to creating and loading UserControls into ContentControls a poor way of creating child controls? Or am I worrying over nothing?
I personally prefer to implement things like this with dependency injection. Typically there will be multiple notifications that need to be made, so start by declaring an interface:
public interface ICustomEventHandler
{
void Event1();
void Event2();
// .. etc
}
Then in the child vm you use dependency injection to inject whatever object needs to watch it:
public class ChildVM
{
[Inject] public ICustomEventHandler Watcher {get; set;}
// .. etc ..
}
First of all this makes mocking very easy, so your unit tests are covered, but more importantly you've formalized the dependencies between this module and the rest of the code and also kept your options open as to how best to implement it. (A simple solution would be for the parent to implement that interface directly and inject itself into the child at creation, in another case you may need to use an intermediate class with singleton scoping or multiple clients).
I am not sure whether this work for you but just my thought.
If you have a MainViewModel which holds your all other ViewModels like the picture above then you can expose Properties/Methods to invoke MainViewModel and Let MainViewModel take the decision to talk to a different ViewModel.

Calling method of UserControl from ViewModel with Caliburn.Micro

I'm writing a ViewModel-first MVVM application using Caliburn.Micro
My View contains a 3rd party UserControl that implements a Method I want/need to call from the associated ViewModel. How do I do that while still upholding the MVVM principles?
There exists an old thread here on SO where a similar question is asked in a more specific context. I would appreciate it if someone could flesh-out the approaches suggested there a bit.
Approach one suggests that the View could subscribe to an IEventAggregator message. But wouldn't I have to use the code behind file to do that? (I thought that was a big no no in MVVM)
Regarding approach two, I have no idea how to do that. And regarding approach three, thats what I tried first but somehow I didn't quite get it to work.
Let me clarify your understanding:
Yes code in the code-behind is generally avoided, but only because MVVM makes it so easy to bind to viewmodel properties and commands in order to wire up your visual element with the functionality behind the scenes
Code that is view-specific in the code-behind of the view is perfectly acceptable assuming it doesn't cross the boundary of concern. For instance, I have a view in my application that does some visual processing of the page, and to do so I require that there is code in the view. This code may also interact with the viewmodel layer, but it will not directly reference the viewmodel, therefore keeping my components loosely coupled
If you have controls that need particular methods calling, then creating an event aggregator message to propagate the notification to the view is perfectly fine since you are still maintaining the separation of concern between the viewmodel and view (and the application components remain encapsulated and testable)
Example View (I've left all event aggregator wire up code and potential dependency injection stuff out for clarity):
public class MyView : IHandle<SomeNotificationMessageType>
{
// Handler for event aggregator messages of type SomeNotificationMessageType
public void Handle(SomeNotificationMessageType message)
{
// Call a method on one of the page controls
SomePageControl.SomeMethod();
}
}
Obviously, what you wouldn't do is something like this in the ViewModel:
public class MyViewModel : IViewAware
{
public void DoSomethingThatAffectsView()
{
var view = this.GetView() as MyView;
view.SomePageControl.SomeMethod();
}
}
Which violates the MVVM principles since you are tightly coupling MyViewModel and MyView.
What if you wanted to use the Context property in caliburn micro which allows multiple views over the same view model? The code above would break - even if you checked the View type, you would still end up with spaghetti code e.g.
public class MyViewModel : IViewAware
{
public void DoSomethingThatAffectsView()
{
var myview = this.GetView() as MyView;
if(myview != null)
myview.SomePageControl.SomeMethod();
var myotherview = this.GetView() as MyOtherView;
if(myotherview != null)
myotherview.SomePageControl.SomeMethod();
// ad infinitum...
}
}
Of course this is subjective: it may be that your usercontrol affects the viewmodel and the view in a complex way, in which case you might want to consider looking at the architecture and working out how that usercontrol can better fit
Have you got any background on what the UC is and what the method on it does?

C# WinForms Model-View-Presenter (Passive View)

I'm developing a WinForms application in C#. I have limited experience in GUI programming, and I am having to learn a great deal on the fly. That being said, here's what I am building.
See the general GUI look at the following link:
GUI http://img227.imageshack.us/img227/1084/program0.jpg
Now, I have done a lot of the work already, but in the very bad Autonomous design pattern. I did not know the project would ever reach a certain size, and, as such, it is time to do some major refactoring.
I have been studying a great deal about GUI design patterns, and the pattern I am wishing to implement is the Passive View (see http://martinfowler.com/eaaDev/PassiveScreen.html). I am looking for some help on how to bring this all together.
Background:
1) Depending on what the user clicks in the "TreeView", the "List" in the bottom left-hand corner will display a list of objects that can populate the "Editor" area. These objects might be a TextBox or a DataGridView. The user toggles the List to choose what he/she wants to see in the "Editor"
2) The model is essentially a folder with data and configuration files. There is an external program that runs on a given directory, creates output files/folders, etc. This program I am developing is designed to effectively manage/configure these objects in a user-friendly way
3) The problem with the way I have been doing things is that it is next to impossible to test, and hence the move to the MVP-esque Passive View design pattern
I am trying to make it so that the program works independently of the View. I have not been able to find any examples where a more complex, interactive view is used with the Passive View pattern.
Questions:
1) Do I need to implement one large interface/view for the entire "look" of the program, then implement sub-interfaces/sub-views for each of the TreeView, Editor, Logger, etc.? Or is there a better "structure" to doing this?
2) When it comes to "handing off" events from the View to the Presenter/Controller (whatever terminology you wish to use W.R.T. the Passive View design pattern), what is the way I should be doing this? Sometimes I have simple properties that need to be updated, and sometimes I need a whole series of steps to unfold.
I would love suggestions and advice on this topic. I have scoured the Internet, and I haven't found adequate examples to help me continue with this project.
Thanks in advance!
Daniel
Here is a simple example that demonstrates the concept of passive views using the MVP design pattern. Because we are using passive views the view has no knowledge of the presenter. The presenter will simply subscribe to events published by the view and act accordingly.
To start out we need to define a contract for our view. This is typically achieved using an interface, essentially, we want to have a very loose coupling with our view. We want the ability to switch to different views or event create mock views for unit testing.
Here is a contract that describes a simple view that will be used to display customer information
public interface ICustomerManagementView
{
void InitializeCustomers(ICustomer[] customers);
void DisplayCustomer(ICustomer customer);
event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}
It exposes a single method InitializeCustomers that will be used to initialize our view with objects from our model.
We also have an event SelectedCustomerChanged that will be used by our presenter to receive notification that an action has occurred in the view.
Once we have our contract we can start to handle these interactions in our presenter.
public class CustomerManagementPresenter
{
private ICustomer _selectedCustomer;
private readonly ICustomerManagementView _managementView;
private readonly ICustomerRepository _customerRepository;
public CustomerManagementPresenter(ICustomerManagementView managementView, ICustomerRepository customerRepository)
{
_managementView = managementView;
_managementView.SelectedCustomerChanged += this.SelectedCustomerChanged;
_customerRepository = customerRepository;
_managementView.InitializeCustomers(_customerRepository.FetchCustomers());
}
private void SelectedCustomerChanged(object sender, EventArgs<ICustomer> args)
{
// Perform some logic here to update the view
if(_selectedCustomer != args.Value)
{
_selectedCustomer = args.Value;
_managementView.DisplayCustomer(_selectedCustomer);
}
}
}
In the presenter we can use another design pattern called dependency injection to provide access to our view and any model classes that we may need. In this example I have a CustomerRepository that is responsible for fetching customer details.
In the constructor we have two important lines of code, firstly we have subscribed to the SelectedCustomerChanged event in our view, it is here that we can perform associated actions. Secondly we have called InitilaizeCustomers with data from the repository.
At this point we haven't actually defined a concrete implementation for our view, all we need to do is create an object that implements ICustomerManagementView. For example in a Windows Forms application we can do the following
public partial class CustomerManagementView : Form, ICustomerManagementView
{
public CustomerManagementView()
{
this.InitializeComponents();
}
public void InitializeCustomers(ICustomer[] customers)
{
// Populate the tree view with customer details
}
public void DisplayCustomer(ICustomer customer)
{
// Display the customer...
}
// Event handler that responds to node selection
private void CustomerTreeViewAfterSelect(object sender, TreeViewEventArgs e)
{
var customer = e.Node.Tag as ICustomer;
if(customer != null)
{
this.OnSelectedCustomerChanged(new EventArgs<ICustomer>(customer));
}
}
// Protected method so that we can raise our event
protected virtual void OnSelectedCustomerChanged(EventArgs<ICustomer> args)
{
var eventHandler = this.SelectedCustomerChanged;
if(eventHandler != null)
{
eventHandler.Invoke(this, args);
}
}
// Our view will raise an event each time the selected customer changes
public event EventHandler<EventArgs<ICustomer>> SelectedCustomerChanged;
}
If we wanted to test our presentation logic we could mock our view and perform some assertions.
EDIT : Included custom event args
public class EventArgs<T> : EventArgs
{
private readonly T _value;
public EventArgs(T value)
{
_value = value;
}
public T Value
{
get { return _value; }
}
}
I would break them down into separate views with their own presents, and use a "controlling" presenter / view to manage message delegation between them all. Not only will this aid testability but it'll keep your controls fulfilling SRP, too.
So in your case you might have an IFormManager which your main window will implement, and then an IFileManager, ILoggerWindow etc. etc.
Although it might be a bit overkill to use, I would suggest that you have a look at Smart Client Software Factory (from the Microsoft Patterns and Practices team) - it's not being actively developed any more, but it has a good implementation of MVP and does this sort of view composition stuff quite well, so might give you some good ideas.

Categories

Resources