WPF, MVVM, Navigation, Keeping Dependency Injection In-Tact - c#

I have a simple WPF application which utilizes the Unity Framework for Dependency Injection. Currently, I am trying to simplify my method for navigation between views in my MVVM pattern implementation; however, many of the examples throughout Stack Overflow do not take into consideration the Dependency Injection caveat.
I have two entirely separate views.
One, Main acts as the main window into which content is loaded (pretty typical; unnecessary content eliminated):
<Window x:Class="Application.UI.Main">
<Grid Background="White">
<ContentControl Content="{Binding aProperty}"/>
</Grid>
</Window>
The constructor receives a ViewModel via constructor injection (again, very simple):
public partial class Main
{
private MainViewModel _mainViewModel;
public Main (MainViewModel mainViewModel)
{
InitializeComponent();
this.DataContext = _mainViewModel = mainViewModel;
}
}
I then have a UserControl, Home, to which I want to "navigate" the main window (i.e. set the ContentControl. It's constructor also receives a ViewModel via constructor injection in the same way Main does. It is equally simple:
public Home(HomeViewModel homeViewModel)
{
InitializeComponent();
// Set Data Context:
this.DataContext = homeViewModel;
}
The main problem, here, is that I want to enable constructor-based injection while maintaining as pure an MVVM implementation as possible.
I am in the View-first camp of MVVM, about which you can find a good discussion in these comments.
I have seen some allusions to the idea of a navigation based service; however, am unsure if that maintains the separation of concerns strived for by MVVM. DataTemplates require View constructors that do not take arguments and I have read criticisms of DataTemplates that argue ViewModels should not participate in the instantiation of Views.
This solution (in my opinion) is just straight wrong as the ViewModel becomes aware of its View and relies on a service for ViewModel instantiaion which makes real Dependency Injection to resolve ViewModel and View dependencies all but impossible. This issue is very evident in the use of RelayCommand in this MSDN article.
Does a navigation service which maintains a global, singleton-like reference to the Main view make the most sense? Is it acceptable for the Main view to expose a method, e.g.:
public void SetContent(UserControl userControl) { //... }
That is then accessed by that service?

This is my articulation of the motivations behind my implementation of the solution provided by another author. I do not provide code as great code examples are provided by the linked article. These are, of course, my opinions but also represent an amalgamation of my research into the topic
No-Container Needed Solution
Rachel Lim wrote a great article, Navigation with MVVM, which describes how to take full advantage of WPF's DataTemplates to solve the challenges presented by MVVM navigation. Lim's approach provides the "best" solution as it greatly reduces the need for any Framework dependencies; however, there really is no "great" way to solve the problem.
The greatest objection to Rachel's approach in general is that the View Model then becomes responsible for - or, "defines" - it's own relationship to the View. For Lim's solution, this is a minor objection for two reasons (and does nothing to further justify other bad architectural decisions, described later):
1.) The DataTemplate relationship is not enforced by anything other than an XAML file, i.e. the View Models are, themselves, never directly aware of their Views nor vice versa, so, even our View's constructor is further simplified, take for example the Home class constructor - now without need for a reference to a View Model:
public Home()
{
InitializeComponent();
}
2.) As the relationship is expressed nowhere else, the association between a particular View and View Model is easy to change.
An application should be able to function (model the domain) sufficiently without a prescribed View. This ideal stems from the effort to best decouple the application's supporting architecture and to foster further application of SOLID programming principles, most specifically dependency injection.
The XAML file - not a third-party dependency container - becomes the pivotal point for resolution of the relationship between the View and the View Model (which, consequently, directly contradicts the OP).
Dependency Injection
An application should be designed to be entirely agnostic of its container and - even better - any implementation-specific information regarding service dependencies. What this allows us to do is to "assign" (inject) services that oblige by a certain contract (interface) to various classes that make up the meat of our applications' functionality.
This leaves us with two criteria for "good design":
Application classes should be able to support a variety of services that perform the same task, as long as they oblige by a described contract.
Application classes should never be aware of - or reference - their container, even if the container is Unity, PRISM, or Galasoft.
The second point is of utmost importance and is a "rule" that is broken, commonly. That "rule breaking" being the inspiration behind the original post.
The response to the navigation problem in many applications is to inject a wrapped dependency injection container which is then used to make calls out of the implementing class to resolve dependencies. The class now knows about the container and, worse, has even greater, more concrete knowledge of what specifics it needs in order to perform its operations (and some might argue more difficult to maintain).
Any knowledge of a dependency resolution container on the part of the View, View Model, or Model is an anti-pattern (you can read more about the justification for that statement elsewhere).
A well written application that relies on dependency injection could function without a dependency injection Framework, i.e. you could resolve the dependencies, manually, from handwritten bootstrapper (though that would require a great deal of careful work).
Lim's solution enables us to "not need" a reference to a container from within the implementation.
What we should be left with are constructors that look like:
// View:
public Home() { //... }
// View Model
public HomeViewModel (SomeModelClass someModel, MaybeAService someService)
If one goal is modularization and reusability, then the above achieves that, well. We could continue to abstract this out further by ensuring those passed-in dependencies are contract fulfillments via interfaces.

Related

Avoid circular refence while classes have to communicate with eachother (Dependency injection)

I'm working on an application written in C# and WPF.
There's a view with a layout that consists of three separated sections (sub views).
A "content" view that contains the current main content (say, a listview of products).
A view located on top of it, containing tools and option
controls.
The main menu view on the left.
I use the .NET dependency injection for my application (Microsoft.Extensions.DependencyInjection, Microsoft.Extensions.Configuration.Abstractions)
When a ViewModel is set for the content view, I also want to set a ViewModel for the top view. These ViewModels have to communicate/reference eachother.
Like, when a command on the top ViewModel is executed, the content ViewModel should be notified and/or do something, and vice-versa.
Say I have a TopViewModel and a ContentViewModel.
One bad thing I could do is:
Requiring the ContentViewModel in the constructor of TopViewModel
and requiring the TopViewModel in the constructor of ContentViewModel.
Of course that won't work, because it's a circular reference.
The alternative I can think of, is just requiring the TopViewModel in the constructor of ContentViewModel and don't do this same kinf of thing with the other class.
The constructor code of ContentViewModel could then listen to events of TopViewModel. The TopViewModel doesn't know anything about ContentViewModel, which can be a problem if it needs to reference it for some logical reason.
Some content views can have multiple top views (they change like when the user selects something)
I'm taking this quite serious. Everything I can think of seems ugly and bad practice to me. While I think this is a quite simple and common situation.
What is the best, generally accepted solution to this that doesn't break the OOP rules?
What is the best, generally accepted solution to this that doesn't break the OOP rules?
Instead of storing a direct reference from one view model to another, you should consider using an event aggregator to communicate between the view models in a loosely coupled way.
This removes the tight coupling between the view model classes and makes your application easier to maintain and evolve over time.
The idea is that a subscriber observes the event aggregator instead of the publisher and the publisher knows only about the event aggregator and not about the subscriber(s). Please refer to the following blog post for more information.
Using the event aggregator pattern to communicate between view models

Separate project for view models to "enforce" MVVM: How do I open dialogs?

Opening dialogs while adhering to the MVVM pattern seems to be one of the regular questions (here and elsewhere). I know there are frameworks like MVVM light who have answers to that problem, but I'm currently working on a very small personal project where I try to do most of the stuff myself for learning purposes.
To "force" myself to pay attention to the references, I decided to extract the view models from the UI project and put them into a separate assembly. The UI project references UI.ViewModels, but not the other way round. This led to me having problems with opening (modal) dialog windows.
Many people seem to be using a DialogService which does something along the lines of:
internal class DialogService : IDialogService
{
public bool? OpenDialog(ViewModelBase vm)
{
Window window = new Window();
window.Content = vm;
return window.ShowDialog();
}
}
The corresponding window content can be inferred from the view model type by using a DataTemplate.
In my scenario though, this doesn't work since the DialogService needs to be in the UI project, but I have to call it from a view model. I could of course abuse DI/IoC to inject an IDialogService implementation into my view models, but that's not what I want to do.
Is there any rigorous way to get this to work?
As an alternative, I have added the following code to my ViewModelBase:
public abstract class ViewModelBase : INotifyPropertyChanged
{
...
public event Action<ViewModelBase, Action<bool?>> Navigate;
protected virtual void OnNavigate(ViewModelBase vm, Action<bool?> callback)
{
Navigate?.Invoke(vm, callback);
}
}
Obviously, there could be more overloads, other parameters, EventArgs and so on; and I should probably put this into an interface as well. But it's just a 'thought' so far.
When creating a view instance (either via resolving or e.g. in the NavigationService, see below), I can let a NavigationService subscribe to that event and invoke the callback. Is this a problematic/bad idea? What are the cons of this? So far (without testing much), one thing I don't like is that I cannot continue in the next line after opening the dialog, but have to continue inside the callback code. That also makes it harder to follow the program flow by reading the code.
Any input is greatly appreciated! This is a very interesting topic, and since many many answers to these questions on SO are quite dated, I hope to learn more about the current best practices :)
In my scenario though, this doesn't work since the DialogService needs to be in the UI project, but I have to call it from a view model.
The IDialogService interface should be defined in the view model project. The view models only know about this interface and you can easily provide a mock implementation of it in your unit tests that simply returns a bool? without actually creating a dialog.
The concrete implementation of the IDialogService, i.e. the DialogService class that creates the window, should on the other hand be implemented in the UI project.
I could of course abuse DI/IoC to inject an IDialogService implementation into my view models, but that's not what I want to do.
This is not an abuse of the depenedency injection pattern. It's rather a typical and correct use of it. I use it myself and it works wonders.
Your alternative solution of extending the view model base class to provide some kind of dialog functionality seems just messy and wrong to me. I would certainly stick with injecting the IDialogService interface into all view models that actually require a dialog service. This is the same as injecting them with any other service.
Why injecting class implementing IDialogService into the viewmodels abuses IoC? I think it's a good way to do this.
Don't overthink this, separating views and logic projects is a good idea, just use whatever works for you.
In my last project I have used Interaction class from ReactiveUI framework. It works well with dialogs and file pickers. I think it closely resembles your alternative, you can check the code and examples.
It's using Reactive Extensions, but you should get the idea.

Use Singleton for model OR where to inject model into viewmodel?

Normally I'd just use a singleton pattern for the model class Logbook. However, I'm trying to move towards learning about DI and want to inject the model into my viewmodel. In addition, I'm planning on having different child windows that open for various function (choose which logbook entries to display, sort order, add a logbook entry, etc) that may or may not need access to the model. What are the pros and cons of using the singleton pattern vs DI with these constraints? In addition, is DI possible if a lot of my viewmodels need access to this model? Finally, where/how should I instantiate the view, viewmodel, and model to be able to inject?
When you're using dependency injection, the idea is to provide classes with a specific implementation of the dependency it needs, so when you're unit testing, you can provide a mock or stub implementation. This is known as loose coupling.
Singletons, meanwhile, are global state that you have no control over. If your class accesses a singleton, it's tightly coupled to the singleton. How do you mock a singleton? In general, you don't. You're stuck to it, and suddenly you have untestable code. Singletons are generally considered an anti-pattern for exactly this reason. (Aside: there are ways around that, but the basic design problem still exists)
Even worse, if something in your class mutates the state of the singleton, this can have side effects in other tests you're writing and make it very difficult to figure out why Test B passes when run alone, but fails if it's run after Test A.
My rule of thumb is Don't use singletons, ever.
Your specific question sounds a little bit fishy. Your viewmodel shouldn't need a model injected into it. It sounds like you want a class responsible for retrieving or otherwise constructing your model, and then you'd inject an implementation of that class into your viewmodel.

MVVM with Unity and Unit Testing architectural design

I'm building a Visual Studio-like application in WPF and I'm having some problems identifying the best architectural design organization of my components. I plan to use Unity as my dependency-injection container and Visual Studio Unit Testing framework and probably moq for mocking library.
I'll first describe the structure of my solution, then my questions:
I have a WPF project that contains:
My Unity container initialization (bootstrapper) on application startup (in App.xaml.cs)
All my application Views (XAML).
Another project called ViewModel this contains:
All my application ViewModels. All my ViewModels inherit from a ViewModelBase which exposes a ILogger property
My initialization logic is as follows:
Application Startup
Unity container creation and registration of types: MainView and MainViewModel
Resolve my MainView and show it.
var window = Container.Resolve<MainView>();
window.Show();
My MainView constructor receives a MainViewModel object in its constructor:
public MainView(MainViewModel _mvm)
My MainViewModel has a Child ViewModel for each of its panels:
public ToolboxViewModel ToolboxVM{get; set;}
public SolutionExplorerViewModel SolutionExplorerVM { get; set; }
public PropertiesViewModel PropertiesVM { get; set; }
public MessagesViewModel MessagesVM { get; set; }
And I'm planning to create a InitializePanels() method that initializes each of the panels.
Now here my questions:
How can my MainViewModel.InitializePanels() initialize all those panels? given the following options:
Option 1: Initialize the ViewModels manually:
ToolboxVM = new ToolboxViewModel();
//Same for the rest of VM...
Cons:
I'm not using the Unity container so my dependencies (e.g. ILogger) are not automatically resolved
Option 2: Use setter injection by annotating my properties:
[Dependency]
public ToolboxViewModel ToolboxVM{get; set;}
//... Same for rest of Panel VM's
Cons:
I've read that Unity Setter dependencies should be avoided since they generate a dependency with Unity in this case
I've also read that you should avoid using Unity for Unit Tests, so how to make this dependency clear in my Unit Tests? Having many dependent properties could be a nightmare to configure.
Option 3: Use Unity Constructor injection to pass ALL my Panel ViewModels to the MainViewModel constructor so they are automatically resolved by Unity container:
public MainViewModel(ToolboxViewModel _tbvm, SolutionExploerViewModel _sevm,....)
Pros:
The dependency would be evident and clear at time of creation, which could help building my ViewModel UnitTests.
Cons:
Having so many constructor parameters could get ugly pretty quickly
Option 4: Registering all my VM types at container buildup. Then passing the UnityContainer instance through constructor injection to my MainViewModel:
public MainViewModel(IUnityContainer _container)
That way I could do something like:
Toolbox = _container.Resolve<ToolboxViewModel>();
SolutionExplorer = _container.Resolve<SolutionExplorerViewModel>();
Properties = _container.Resolve<PropertiesViewModel>();
Messages = _container.Resolve<MessagesViewModel>();
Cons:
If I decide NOT to use Unity for my UnitTests, as many people suggest,then I won't be able to resolve and initialize my Panel ViewModels.
Given that lengthy explanation, what is the best approach so that I can take advantage of a Dependency Injection Container and end up with a Unit-Testable solution??
Thanks in advance,
First things first... As you noticed, your current setup might be problematic when unit testing (complex VM initialization). However, simply following DI principle, depend on abstractions, not on concretions, makes this problem go away immediately. If your view models would implement interfaces and dependencies would be realized through interfaces, any complex initialization becomes irrelevant as in test you'll simply use mocks.
Next, problem with annotated properties is that you create high coupling between your view model and Unity (this is why it is most likely wrong). Ideally, registrations should be handled at single, top level point (which is bootstrapper in your case), so container is not bound in any ways to object it provides. Your options #3 and #4 are most common solutions for this problem, with few notes:
to #3: too many constructor dependencies is usually mitigated by grouping common functionality in facade classes (however 4 is not that many after all). Usually, properly designed code doesn't have this problem. Note that depending on what your MainViewModel does maybe all you need is dependency to list of child view models, not concrete ones.
to #4: you shouldn't use IoC container in unit tests. You simple create your MainViewModel (via ctor) manually and inject mocks by hand.
I'd like to address one more point. Consider what happens when your project grows. Packing all view models into single project might not be good idea. Each view model will have its own (often unrelated to others) dependencies, and all this stuff will have to sit together. This might quickly become difficult to maintain. Instead, think whether you can extract some common functionalities (for example messaging, tools) and have them in separate groups of projects (again, split into M-VM-V projects).
Also, it's much easier to swap views when you have functionality related grouping. If project structure looks like this:
> MyApp.Users
> MyApp.Users.ViewModels
> MyApp.Users.Views
> ...
Trying out different view for user edit window is a matter of recompiling and swapping single assembly (User.Views). With all in one bag approach, you'll have to rebuild much larger part of application, even tho majority of it haven't changed at all.
Edit: keep in mind that changing existing structure of project (even tiny one), is usually a very costly process with minor/none business results. You might not be allowed or simply not be able to afford doing so. Usage-based (DAL, BLL, BO, etc) structure does work, it just gets heavier with time. You can just as well use mixed mode, with core functionalities grouped by their usage and simply adding new functionalities utilizing modular approach.
First off, you'd probably want to use interfaces rather than concrete classes, so that you'll be able to pass you mock objects when unit testing, i.e IToolboxViewModel instead of ToolboxViewModel, etc.
That being said, I would recommend the third option - constructor injection. This makes the most sense, since otherwise you could call var mainVM = new MainViewModel() and end up with a non-functional view model. By doing that, you're also making it very easy to understand what are your view-model's dependencies, which makes it easier to write unit tests.
I would check out this link, as it's relevant to your question.
I agree with Lester's points but wanted to add a few other options and opinions.
Where you are passing the ViewModel to the View through the constructor, this is a bit unconventional as WPF's binding capability allows you to completely decouple the ViewModel from the View by binding to the DataContext object. In the design you've outlined, the View is coupled to a concrete implementation and limits reuse.
While a service facade will simplify option 3, it is not uncommon (as you've outlined) for top-level ViewModels to have a lot of responsibilities. Another pattern you can consider is a controller or factory pattern that assembles the viewmodel. The factory can be be backed by the container to do the work but the container is abstracted away from the caller. A key goal in building container-driven apps is to limit the number of classes that understand how the system is assembled.
Another concern is the amount of responsibilities and object relationships that belong to the top-level viewmodel. If you look at Prism (a good candidate with WPF + Unity) it introduces the concept of "regions" that are populated by modules. A region may represent a toolbar which is populated by mutliple modules. Under such a design, the top-level viewmodel has fewer responsibilities (and dependencies!) and each module contains Unit-testable DI components. Big shift in thinking from the example you've provided.
Regarding option 4, where the container is passed in through the constructor is technically dependency inversion but it's in the form of service location instead of dependency injection. Having gone down this path before I can tell you it's a very slippery slope (more like a cliff): Dependencies are hidden inside classes and your code becomes a web of "just in time" madness -- completely unpredictable, totally untestable.

How should my model look like?

As I am further digging into MVVM and MVVM-light I recognized, that there is no MVVM-light provided base class for models.
But from my understanding, messaging and raising notifications could also happen in a model. At least in communication between models I would find that messaging would come in very handy.
So I just decided to derive my Model from ViewModelBase, even though some of the properties (like the design time ones) will be unused.
But the more I am looking at this, the more I think I have missed something. Is it considered "bad practice" to derive my Models from ViewModelBase?
And is it ok to use Messaging for Model communication?
Derive your view-model classes from whatever you like... MVVM-light offers the VieWModelBase to provide an implementation of ICleanUp - which is good for managing the life-cycle of ViewModel objects. My own choice has been to implement all scaffolding for Property Change notifications in a base class, then derive from that for model classes. About the only strong suggestions I have regarding model classes are:
Once size doesn't fit all. How you store your data may be different from how you interact with data, and ViewModel objects should be geared towards supporting interaction, not storage, and if you need to interact with the same data (Model) in two very different ways, then design two different ViewModels to support these different interactions.
Do use attributes (a la System.ComponentModel) to annotate the models. You can get a lot of your validation work done this way - and validation feedback is the responsibility of the presentation layer (View + ViewModel), not the problem domain (i.e. the Model).
Really good ViewModel classes are also usually stateless enough that they can be recycled/reused within a single user interaction, such that large data lists can be virtualized (WPF supports virtualization) to save RAM.
Remember DRY (Do Not Repeat Yourself), KISS (Keep It Simple, Stupid!) and YAGNI (You ain't gonna need it) - are the principles you should keep in mind above any academic design principles. I've litereally wasted weeks on a WPF app implementing academically perfect MVC/MVVM patterns, only to find that they detracted form the overall understandability of the finished solution. So... keep it simple! :)
I would take a look at the EventAggregator in the Composite Application Library. The answer in this post has a good description of it. Jeremy Miller's post goes into a bit more detail.

Categories

Resources