Is this design pattern code smell? How to achieve this using DI? - c#

I'm writing a WPF application using MVVM. My ViewModels are quite large and have a lot of logic associated with them (filtering, searching, writing to the database, etc), so I've decided to try to separate out the logic of the ViewModels to a "Presenter" class like is used in MVP.
So, my basic setup is this:
public class FooViewModel : ViewModelBase, IFooViewModel
{
private IFooPresenter presenter;
private ObservableCollection<FooModel> fooCollection;
public FooViewModel()
{
presenter = FooPresenter(this);
}
public ObservableCollection<FooModel> FooCollection
{
get { return fooCollection; }
set
{
fooCollection = value;
OnPropertyChanged("FooCollection");
}
}
public void FooCommandMethod(object obj)
{
presenter.DoStuff();
}
}
public class FooPresenter : IFooPresenter
{
private IFooViewModel viewModel;
public FooPresenter(IFooViewModel viewModel)
{
this.viewModel = viewModel;
}
public void DoStuff()
{
viewModel.FooCollection.Add(new FooModel());
//etc etc, make whatever ViewModel updates are needed
}
}
I feel like it is bad practice to have this circular dependency (View Model depends on Presenter and Presenter depends on View Model). These classes could be combined into one large ViewModel class, but I do like how clean this approach keeps my View Models, all that they do is hold commands that call presenter functions and hold the Model/collections of the Model. I also dislike the dependency of the ViewModel on the concrete implementation of the Presenter. One approach I have toyed with is using a Service Locator type class, so it would look like this:
public FooViewModel()
{
presenter = PresenterLocator.GetPresenter<IFooPresenter>(this);
}
What I would prefer, though, is to use Constructor Dependency Injection to inject the controller when I create the ViewModel. The problem with this is that this creates a circular dependency in the constructors of the ViewModels and Presenters, which causes my application to crash when I attempt to achieve this using Unity. It ends up looking like this:
public FooViewModel(IFooPresenter presenter)
{
this.presenter = presenterl
}
And
public FooPresenter(IFooViewModel viewModel(
{
this.viewModel = viewModel;
}
So, my concern is that my design approach is inherently flawed due to this. Nevertheless, I really like how clean it keeps my ViewModels and separates them from Business Logic. Is there a better way I could be designing this? Is there any way I can use DI to achieve this? Or by doing that am I essentially trying to force a DI container to act as a Service Locator?

First of all, I would not call this a "presenter". This introduces an unwanted confusion, in fact your presenter doesn't present anything, it is just an extracted bit of code from a large view model. Have you considered calling it just "a service"? A SearchService for example?
Another question is: does such service always depend on a view model? Or rather, could it depend on lower layers (unit of works/repos for example) or other services? Note that because your service depends on a view model and you pass a view model directly there, you loose a control of what happens to the view model inside a service. Your DoStuff method is a perfect example, it does something to a view model, alters its state. Instead, you could have
public class FooViewModel : ViewModelBase, IFooViewModel
{
private IFooService service;
private ObservableCollection<FooModel> fooCollection;
public FooViewModel()
{
service = FooService(this);
}
public void FooCommandMethod(object obj)
{
// the responsibility on consuming service outcome is still here!
this.FooCollection.Add( service.CreateNewModel() );
}
}
public class FooService : IFooService
{
// constructor parameter not needed now
public FooService()
{
this.viewModel = viewModel;
}
public FooModel CreateModel()
{
return ...;
}
}
If you still insist however on having a circular dependency, make it so that one of the two has a parameterless constructor and a property injector:
public class FooViewModel : IFooViewModel
{
private IFooService _service;
public FooViewModel( IFooService service )
{
this._service = service;
this._service.Model = this;
}
}
public class FooService : IFooService
{
public IFooViewModel Model { get; set; }
}
This way Unity asked for a IFooViewModel will resolve a parameterless IFooService and then execute the constructor that sets the cycle for both parties.

Related

How to fix a Circular Dependency

So I've just recently started using the Microsoft.Extensions.DependencyInjection nuget package in my WPF project because I wanted to start learning more about DI.
Issue
I keep getting a Circular Dependency Exception whenever I try to access a dependency from any other ViewModel besides the MainViewModel
This is what I have done so far.
I've installed these two Nuget packages into my project
Microsoft.Extensions.Hosting --version 7.0.0
Microsoft.Extensions.DependencyInjection --version 7.0.0
And then I went ahead and created my container inside my App.xaml.cs
public partial class App : Application
{
private readonly ServiceProvider _serviceProvider;
public App()
{
IServiceCollection _services = new ServiceCollection();
_services.AddSingleton<MainViewModel>();
_services.AddSingleton<HomeViewModel>();
_services.AddSingleton<SettingsViewModel>();
_services.AddSingleton<DataService>();
_services.AddSingleton<NavService>();
_services.AddSingleton<MainWindow>(o => new MainWindow
{
DataContext = o.GetRequiredService<MainViewModel>()
});
_serviceProvider = _services.BuildServiceProvider();
}
protected override void OnStartup(StartupEventArgs e)
{
var MainWindow = _serviceProvider.GetRequiredService<MainWindow>();
MainWindow.Show();
base.OnStartup(e);
}
}
In my App.xaml I also defined a few DataTemplates which will allow me to display different views based in their DataType
<Application.Resources>
<DataTemplate DataType="{x:Type viewModel:HomeViewModel}">
<view:HomeView/>
</DataTemplate>
<DataTemplate DataType="{x:Type viewModel:SettingsViewModel}">
<view:SettingsView/>
</DataTemplate>
</Application.Resources>
Then I went ahead and created my MainWindow.xaml
<Window x:Class="Navs.MainWindow"
...>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Border>
<StackPanel>
<Button Height="25" Content="Home" Command="{Binding HomeViewCommand}"/>
<Button Height="25" Content="Settings" Command="{Binding SettingsViewCommand}"/>
</StackPanel>
</Border>
<ContentControl Grid.Column="1" Content="{Binding NavService.CurrentView}">
</ContentControl>
</Grid>
</Window>
And a corresponding ViewModel
public class MainViewModel : ObservableObject
{
private NavService _navService;
public NavService NavService
{
get => _navService;
set
{
_navService = value;
OnPropertyChanged();
}
}
/* Commands */
public RelayCommand SettingsViewCommand { get; set; }
public RelayCommand HomeViewCommand { get; set; }
public MainViewModel(NavService navService, HomeViewModel homeViewModel, SettingsViewModel settingsViewModel)
{
NavService = navService;
HomeViewCommand = new RelayCommand(o => true, o => { NavService.CurrentView = homeViewModel; });
SettingsViewCommand = new RelayCommand(o => true, o => { NavService.CurrentView = settingsViewModel; });
}
}
As you can see, with the help of Dependency Injection, I can now access the objects I've registered in my container through the constructor.
I've also created two UserControls
UserControl1
<Grid>
<StackPanel VerticalAlignment="Center">
<Button Height="25" Content="Click me" Command="{Binding OpenWindowCommand}" />
<Button Content="Settings View" Command="{Binding SettingsViewCommand}" Height="25" />
</StackPanel>
</Grid>
And it's corresponding ViewModel
public class HomeViewModel
{
public RelayCommand SettingsViewCommand { get; set; }
public HomeViewModel()
{
}
}
And then we have UserControl2
<Grid>
<StackPanel VerticalAlignment="Center">
<TextBox Text="{Binding Message}"
Height="25"/>
<Button Height="25" Content="Home View" Command="{Binding HomeViewCommand}"/>
<Button Height="25" Content="Fetch" Command="{Binding FetchDataCommand}"/>
</StackPanel>
</Grid>
With it's corresponding ViewModel
public class SettingsViewModel : ObservableObject
{
public string Message { get; set; }
public RelayCommand HomeViewCommand { get; set; }
public RelayCommand FetchDataCommand { get; set; }
public SettingsViewModel()
{
}
}
The NavService.cs
public class NavService : ObservableObject
{
private object _currentView;
public object CurrentView
{
get => _currentView;
set
{
_currentView = value;
OnPropertyChanged();
}
}
private HomeViewModel HomeViewModel { get; set; }
private SettingsViewModel SettingsViewModel { get; set; }
public NavService(HomeViewModel homeViewModel, SettingsViewModel settingsViewModel)
{
HomeViewModel = homeViewModel;
SettingsViewModel = settingsViewModel;
CurrentView = HomeViewModel;
}
public void NavigateTo(string viewName)
{
switch (viewName)
{
case "Settings":
CurrentView = SettingsViewModel;
break;
case "Home":
CurrentView = HomeViewModel;
break;
}
}
}
This all works just fine, the issue occurs when I take the HomeViewModel and try to pass in the NavService as a constructor.
public HomeViewModel(NavService navService)
{
}
At that point, it throws the exception.
I want to be able to access the NavService from various Views so that I can change the NavService.CurrentView from multiple places.
This is a design issue. The main view model tightly coupled, is acting as a pass through and violating SRP (Single responsibility principle). The navigation service and other view models both explicitly depend on each other, which is the direct cause of the circular dependency issue.
For simplicity, note the following refactor for the NavService
public abstract class ViewModel : ObservableObject {
}
public interface INavigationService {
object CurrentView { get; }
void NavigateTo<T>() where T : ViewModel;
}
public class NavService : INavigationService, ObservableObject {
private readonly Func<Type, object> factory;
private object _currentView;
public NavService(Func<Type, object> factory) {
this.factory = factory;
}
public object CurrentView {
get => _currentView;
private set {
_currentView = value;
OnPropertyChanged();
}
}
public void NavigateTo<T>() where T: ViewModel {
object viewModel = factory.Invoke(typeof(T))
?? throw new InvalidOperationException("Error message here");
CurrentView = viewModel;
}
}
This service when registered should configure the factory used to get the view models.
public partial class App : Application {
private readonly IServiceProvider _serviceProvider;
public App() {
IServiceCollection _services = new ServiceCollection();
_services.AddSingleton<MainViewModel>();
_services.AddSingleton<HomeViewModel>();
_services.AddSingleton<SettingsViewModel>();
_services.AddSingleton<DataService>();
_services.AddSingleton<INavigationService, NavService>()(sp => {
return new NavService(type => sp.GetRequiredService(type));
});
_services.AddSingleton<MainWindow>(o => new MainWindow {
DataContext = o.GetRequiredService<MainViewModel>()
});
_serviceProvider = _services.BuildServiceProvider();
}
protected override void OnStartup(StartupEventArgs e) {
var mainWindow = _serviceProvider.GetRequiredService<MainWindow>();
mainWindow.Show();
base.OnStartup(e);
}
}
This completely decouples the main and other view models but allows for strongly typed navigation and removes the circular dependency since in this particular scenario the models only need know about the navigation service
public class MainViewModel : ViewModel {
private INavigationService _navService;
/* Ctor */
public MainViewModel(INavigationService navService) {
NavService = navService;
HomeViewCommand = new RelayCommand(o => true, o => { NavService.NavigateTo<HomeViewModel>(); });
SettingsViewCommand = new RelayCommand(o => true, o => { NavService.NavigateTo<SettingsViewModel(); });
}
public INavigationService NavService {
get => _navService;
set {
_navService = value;
OnPropertyChanged();
}
}
/* Commands */
public RelayCommand SettingsViewCommand { get; set; }
public RelayCommand HomeViewCommand { get; set; }
}
Note that no changes were needed in the views. The navigation service is also now flexible enough to allow any number of view models to be introduced into the system with no changes needed to be made to it.
It's rarely a good idea to resolve mainwindow out your DI container.
You want that rendered ASAP and what are you going to inject into it's constructor?
Probably nothing.
What are you going to switch it out for?
Probably nothing.
The main practical reason you want interfaces is so you can mock that class in your unit tests.
Everything you build should have a single responsibility.
The mainwindow's job is to contain what you initially show the user. Maybe pretty much everything.
Unit testing UI is quite a challenge so it's common to reduce what goes into it to re-usable components and not write tests.
You should not pass in the concrete versions of viewmodels to mainviewmodel. If it needs to know about them, what do you do when you have 50 views?
public MainViewModel(NavService navService)
{
Navservice should resolve concrete instances on demand. More like.
NavService.CurrentView =
(IInitiatedViewModel)serviceProvider.GetService(typeofregisteredinterface);
The serviceprovider is an instance class. You need some sort of reference to it unless you instantiate absolutely everything in app.xaml.cs resolving everything at start up.
In a real world application, you will need transients. You will not be able to rely on everything being a singleton.
You will want to navigate to a NEW instance of a FooViewModel because you want a new Foo which isn't the same as the last Foo and will not be the same as a future Foo. You will want a new Customer or repository instance.
You will have more complicated things in any real app than two viewmodels.
Note that serviceprovider is:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.serviceprovider?view=dotnet-plat-ext-7.0
Which already has an interface defined IServiceProvider. So you could easily inject a mock for testing purposes.
The serviceprovider you use in app.xaml will need to be referenced somehow.
You usually want the viewmodel interface:
interface IInitiatedViewModel
{
Task Initiate();
}
So you can get any data for your viewmodel after it's instantiated.
public async Task Initiate()
{
Suppliers = await _repository.GetAddressesByTypeAsync((int)AddressType.Supplier);
if(Suppliers.Count == 1)
{
ChosenSupplier = Suppliers[0];
}
}
I suggest you should also have a list somewhere which has Type and Description of your viewmodel and view.
You can then abstract away navigation from specific viewmodel types.
They're choosing whatever the [3] view is and that is called whatever is in description, it's viewmodel interface is whatever is in Type.
If necessary you can then extend this principle to have an optional factory method in there.
And logic can be in your navigation service or another injected class.
Parent viewmodels such as homeviewmodel may have dependencies but they use things rather than get used by something else. There is no real advantage to defining an interface for them because you never really replace them with a moq for tests. That means there's no need to register an interface as being associated with them.
I often find there are a lot of these.
You can define some custom attributes for these and compose your navigation list dynamically. This saves editing separate things.
You don't want to compose this list before you've shown the user the first view so it's usual to resolve HomeViewModel and MainWindowViewModel immediately. You can register these close to your entry point for di if necessary.
Others can be added using reflection.
Hence you could have viewmodels decorated:
[ParentViewModel("Foo View Name Here")]
....
public class FooViewModel()
{
You can find code samples which allow such reflection:
How enumerate all classes with custom class attribute?
As your app grows you might have many views. Iterating all those classes can be done in a console app generates xml or a source generator. You can also have attributes define aspects such as menu location. Because attributes go on classes, they're associated with the code you're writing/maintaining rather than completely disconnected. That means you're less likely to make mistakes like mis spell an enum or fail to remove an obsolete enum entry when you remove an unwanted view.
Attribute driven generation is very powerful.
You could use code generation to generate interfaces and registration for repeated patterns such as views and viewmodels.
You might not find any value in explicitly registering these with the dependency injection container if you do not want a singleton for each.
You can instantiate an instance of an UnregisteredClass using ActivatorUtilities.CreateInstance
ActivatorUtilities.CreateInstance<UnregisteredClass>(serviceProvider);
That will provide any dependencies to your UnregisteredClass.
https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.activatorutilities.createinstance?view=dotnet-plat-ext-7.0&viewFallbackFrom=aspnetcore-2.1#Microsoft_Extensions_DependencyInjection_ActivatorUtilities_CreateInstance__1_System_IServiceProvider_System_Object___
There's an optional parameter which can be useful to provide variable parameters. Like say you want Invoice nnn.
Don't configure the IoC container in the constructor! Move related code to your OnStartup override or the Application.Startup event handler. The constructor is only meant to initialize/configure the instance. The constructor must always return fast.
Your are implementing Dependency Injection wrong. As you have currently implemented it, it defies its purpose. First step is always to follow the Dependency Inversion principle (the D in SOLID): don't depend on concrete types. Rather depend on their abstractions.
This means you have to introduce abstract classes and interfaces. Then only inject those abstractions into your concrete types.
Circular dependencies are usually introduced by designing wrong responsibilities (bad class design). IoC reveals this design flaw because dependencies are now publicly exposed, usually via the constructor.
Circular dependencies exist on constructor level and on class level.
A constructor level and class level circular dependency exist independent of each other and must be fixed separately. Fixing one doesn't fix the other. It's the constructor level circular dependency that throws the InvalidOperationException or StackOverflowException.
From a class level design perspective,
when type A depends on B and B on A (A ⟷ B)
then you have a circular dependency and the following options to fix it:
a) A and Bshould be merged into a single class (A)
b) B has too much responsibility or too much knowledge of A or other classes in general. Move related responsibility back to A. Now B would have to use A to fulfill its responsibility
A ⟷ B ➽ A ⟶ B
c) the shared logic must be moved/extracted to a third type C:
A ⟷ B ➽ A ⟶ C ⟵ B
d) introduce interfaces to invert the dependency (Dependency Inversion principle):
IA
⬀ ⬉
A ⟷ B ➽ A B
⬊ ⬃
IB
This means:
a) A knows how to navigate. This could lead to A having too much responsibility. The proof: every type that needs to navigate also has to implement the complete logic (duplicate code)
b) every type knows where it can/is allowed to navigate to. While the navigation logic is encapsulated by a dedicated type (NavigationService), the actual valid destination is only known to the client. This adds robustness to the code. In you case, this would mean A will have to provide B with arguments to allow B to fulfill its responsibility. B is now unaware of the existence of A (A ➞ B).
c) because the dependency is not introduced to make particular class members (API) available, c) can't be applied in your case. In your case your B depends on A as a type alone (instance and not instance members).
d) because the circular dependency is manifested in the constructor, introducing interfaces alone won't resolve the circular dependency exception thrown by the IoC container (or creator in general).
Three Solutions
To fix your original problem you have three options:
hide the (constructor) dependencies behind a factory (not recommended)
fix your design. The NavigationService knows too much. Following your pattern, NavigationService will have to know every view model class (or every navigation destination) explicitly.
use property injection instead of constructor injection (not recommended)
The following examples will use a Func<TProduct> instead of an abstract factory to simplify the examples.
The examples also use an enum as destination identifier to eliminate the use of magic strings
and assume that you have introduced an interface for each dependency.
It's important to understand that there are basically two circular dependencies: class level and constructor. Both can be resolved individually.
The class level circular dependency is usually resolved by introducing interfaces (applying the Dependency Inversion principle).
The constructor circular dependency is fixed using one of the three below suggestions.
For the sake of completeness, all three suggestions also fix the class level circular dependency (although it is not responsible for the circular dependency exception thrown by the IoC container).
NavigationId.cs
enum which is used by all examples to replace the magic string parameter to identify the navigation destination.
public enum NavigationId
{
None = 0,
HomeScreen,
SettingsScreen
}
Solution 1): Hide dependencies (not recommended)
Instead of depending on explicit types, let your classes depend on (abstract) factories by implementing the Abstract Factory pattern.
Note, there still will be an implicit circular dependency. It is just hidden behind factories. The dependency is just removed from the constructor (constructor dependency - constructing a NavigationService no longer requires the construction of HomeViewModel and vice versa).
As already mentioned, you would have to introduce interfaces (for example a IHomeViewModel) to completely remove the circular dependency.
You will also see that in order to add more destinations you would have to modify the NavigationService too. This is a good indicator that you have implemented a bad design. In fact, you have violated the Open-Closed principle (the O in SOLID).
NavigationService.cs
class NavigationService : INavigationService, INotifyPropertyChanged
{
// Constructor.
// Because of the factory the circular dependency of the constructor
// is broken. On class level the dependency still exists,
// but could be removed by introducing a 'IHomeViewModel' interface.
public NavigationService(Func<IHomeViewModel> homeViewModelFactory)
{
// This reveals that the class knows too much.
// To introduce more destinations,
// you will always have to modify this code.
// Same applies to your switch-statement.
// A switch-statement is another good indicator
// for breaking the Open-Closed principle
this.NavigationDestinationFactoryTable = new Dictionary<NavigationId, Func<object>>()
{
{ NavigationId.HomeScreen, homeViewModelFactory.Invoke()}
};
}
public void Navigate(NavigationId navigationId)
=> this.CurrentSource = this.NavigationDestinationTable.TryGetValue(navigationId, out Func<object> factory) ? factory.Invoke() : default;
public object CurrentSource { get; private set; }
private Dictionary<NavigationId, Func<object>> NavigationDestinationFactoryTable { get; }
}
HomeViewModel.cs
class HomeViewModel : IHomeViewModel, INotifyPropertyChanged
{
private INavigationService NavigationService { get; }
// Constructor
public HomeViewModel(Func<INavigationService> navigationServiceFactory)
=> this.NavigationService = navigationServiceFactory.Invoke();
}
App.xaml.cs
Configure the IoC container to inject the factories. In this example the factories are simple Func<T> delegates. For more complex scenarios you probably want to implement abstract factories instead.
protected override void OnStartup(StartupEventArgs e)
{
IServiceCollection _services = new ServiceCollection();
// Because ServiceCollection registration members return the current ServiceCollection instance
// you can chain registrations
_services.AddSingleton<IHomeViewModel, HomeViewModel>()
.AddSingleton<INavigationService, NavigationService>()
/* Register the factory delegates */
.AddSingleton<Func<IHomeViewModel>>(serviceProvider => serviceProvider.GetRequiredService<HomeViewModel>)
.AddSingleton<Func<INavigationService>>(serviceProvider => serviceProvider.GetRequiredService<NavigationService>);
}
Solution 2): Fix the class design/responsibilities (recommended)
Every class should know the navigation destinations it is allowed to navigate to. No class should know about an other class where it can navigate to or if it can navigate at all.
Opposed to solution 1), the circular dependency is completely lifted.
NavigationService.cs
public class NavigationService : INavigationService, INotifyPropertyChanged
{
// The critical knowledge of particular types is now removed
public NavigationService()
{}
// Every class that wants to navigate to a destination
// must know/provide his destination explicitly
public void Navigate(object navigationDestination)
=> this.CurrentSource = navigationDestination;
public object CurrentSource { get; private set; }
}
HomeViewModel.cs
class HomeViewModel : IHomeViewModel, INotifyPropertyChanged
{
private INavigationService NavigationService { get; }
// Constructor
public HomeViewModel(INavigationService navigationService)
=> this.NavigationService = navigationService;
}
Solution 3): Property injection
Property injection is not supported by the .NET dependency injection framework. However, property injection is generally not recommended. Aside from hiding dependencies, it imposes the danger of accidentally making a bad class design work instead of fixing what really needed to be fixed (as it would be the case with this example).
While 2) is the recommended solution, you can combine both solutions 1) and 2) and decide how much the particular navigation source needs to know about destinations.
public class NavigationService : INavigationService, INotifyPropertyChanged
{
public Navigator(Func<IHomeViewModel> homeViewModelFactory)
{
this.HomeViewModelFactory = homeViewModelFactory;
// This reveals that the class knows too much.
// To introduce more destinations,
// you will always have to modify this code.
// Same applies to your switch-statement.
// A switch-statement is another good indicator
// for breaking the Open-Closed principle
this.NavigationDestinationFactoryTable = new Dictionary<NavigationId, Func<object>>()
{
{ NavigationId.HomeScreen, homeViewModelFactory }
};
}
public void Navigate(NavigationId navigationId)
=> this.CurrentSource = this.NavigationDestinationTable.TryGetValue(navigationId, out Func<object> factory) ? factory.Invoke() : default;
public void Navigate(object navigationDestination)
=> this.CurrentSource = navigationDestination;
public object CurrentSource { get; private set; }
public Func<IHomeViewModel> HomeViewModelFactory { get; }
private Dictionary<NavigationId, Func<object>> NavigationDestinationFactoryTable { get; }
}
Then improve the MainViewModel initialization and clean up its dependencies.
It should use the NavigationService instead of explicit assignment.
That's why it got an NavigationService injected:
MainViewModel.cs
public class MainViewModel : INotifyPropertyChanged
{
// Must be read-only
public INavigationService NavigationService { get; }
/* Commands. Must be read-only too */
public RelayCommand SettingsViewCommand { get; }
public RelayCommand HomeViewCommand { get; }
public MainViewModel(INavigationService navigationService)
{
this.NavigationService = navigationService;
this.HomeViewCommand = new RelayCommand(
o => true,
o => this.NavigationService.Navigate(NavigationId.HomeScreen));
this.SettingsViewCommand = new RelayCommand(
o => true,
o => this.NavigationService.Navigate(NavigationId.SettingsScreen));
}
}

Reusing a View on MVVM pattern with EFCore

I'm working with EF Core and MVVM pattern, and I'm not sure how to proceed on how to create a "reusable" view.
I have a view with a menu strip with common operations (CRUD and filtering) and a DataGrid that would be filled via EF Core. I have a bunch of different models (all of which inherit a simple base model class with a single int ID property), and I need to display my data.
Now, according to DRY, since the views are practically identical, I shouldn't create a different view for each model, just create a generic view and fill it accordingly. Also, I've read here that viewmodels aren't usually reusable, so I would need one viewmodel for each model. And here's my question.
When creating my view, I was taught this pattern:
public class StockView : Window
{
private StockViewModel _viewModel;
public StockView(StockViewModel viewModel)
{
InitializeComponent();
_viewModel = viewModel ?? new StockViewModel();
DataContext = _viewModel;
}
}
However, that would mean this view would only accept StockViewModel, so I wouldn't be able to reuse it. I've tried creating an abstract viewmodel base for all viewmodels to inherit from, and created my generic view as
public class GenericView : Window
{
private ViewModelBase _viewModel;
public GenericView(ViewModelBase viewModel)
{
InitializeComponent();
_viewModel = viewModel ?? new ViewModelBase();
DataContext = _viewModel;
}
}
But now, I won't be able to access any of the viewmodel methods that would fetch me data asynchronously. Async abstract methods aren't allowed, and I tried creating a method that would a service class that would return me my data, but I can't use it either:
public class StockService
{
private MyDbContext _context = new MyDbContextFactory().CreateContext();
public async Task<List<Stock>>GetStocksAsync()
{
return await _context.STOCKs.Select(x=>x).ToListAsync();
}
}
public abstract class ViewModelBase
{
public abstract List<EntityBase> GetAllData();
}
public class StockViewModel : ViewModelBase
{
public override List<EntityBase> GetAll()
{
var stockServ= new StockService();
return stockServ.GetStocksAsync().Result; //<==== this doesn't compile as the method expect List<EntityBase> but it returns List<Stock>
}
}
How would I be able to reuse a view for different viewmodels, then?
Async abstract methods aren't allowed ...
No, but async is an implementation detail. An abstact class or an interface may still define a method that returns a Task<T> that you can then implement asynchronously:
public abstract class BaseViewModel<T>
{
public abstract Task<IEnumerable<T>> GetItems();
}
public class StockViewModel : BaseViewModel<Stock>
{
public override async Task<IEnumerable<Stock>> GetItems()
{
await ...
return ...
}
}

How far to separate out business logic in MVVM

Here's a simplified ViewModel:
public class EditViewModel : BaseViewModel
{
private Item _currentItem;
public Item CurrentItem
{
get
{ return _currentItem; }
set
{
if (_currentItem != value)
{
_currentItem = value;
OnPropertyChanged("CurrentItem");
}
}
}
private ObservableCollection<Property> _itemProperties;
public ObservableCollection<Property> ItemProperties
{
get { return _itemProperties; }
set
{
_itemProperties = value;
OnPropertyChanged("ItemProperties");
}
}
public void AddProperty() //this is called from an ICommand
{
Property p = new Property{ ItemId = CurrentItem.ItemId };;
CurrentItem.Properties.Add(p);
ItemProperties.Add(p);
}
}
What I'd like to do is to separate out the business logic here into a separate class. It keeps all the annoying MVVM boilerplate out of the way of the useful stuff, and in theory should lead to organizing the code into a more testable state.
We're starting to do this by creating separate "Logic" classes which inherit from BaseViewModel and then have the actual ViewModels inherit from their logic class. So:
public class EditLogic : BaseViewModel
{ }
public class EditViewModel : EditLogic
{ }
Then the logic goes in the logic class.
For some business logic this separation is simple - nice and clean. However, in the example I've given above I can't see a simple way of pulling that method out without a lot of unnecessary faff. Something like this (untested):
public class EditLogic : BaseViewModel
{
public Property GetNewProperty(Item currentItem)
{
Property p = new Property{ ItemId = currentItem.ItemId };
currentItem.Properties.Add(p);
return p;
}
}
public class EditViewModel : BaseViewModel
{
public void AddProperty() //this is called from an ICommand
{
ItemProperties(GetNewProperty(CurrentItem))
}
}
This seems potentially confusing - since it's relying on CurrentItem implicitly being passed by reference - and unnecessarily convoluted to no great gain.
This is, of course, a very simple example which isn't worth fussing over. But it illustrates the point that in MVVM it's very easy to end up mixing your presentation/binding code with your business logic for the sake of convenience.
I could move some of the properties out from the EditViewModel to the EditLogic but then we're losing the advantages of separating these two out in the first place.
So: is it worth bothering with this at all? If so, how far should we pursue it? And are there any better methods for maintaining separation?
What you are looking for are services.
public interface IPropertyService
{
Property GetNewProperty(Item currentItem);
}
You will of course need an implementation:
public class MyPropertyService : IPropertyService
{
public Property GetNewProperty(Item currentItem)
{
//TODO
}
}
You can then inject this service into the constructor of your view model as a dependency.
public class MyViewModel
{
private IPropertyService _PropertyService;
public MyViewModel(IPropertyService propertyService)
{
_PropertyService = propertyService;
}
public void AddProperty() //this is called from an ICommand
{
Property p = _PropertyService.GetProperty(CurrentItem);
CurrentItem.Properties.Add(p);
ItemProperties.Add(p);
}
}
This will ensure that you don't need to create a myriad of view model base classes for your business logic. Instead, encapsulate your business logic in services and pass them into view models that depend on them.

How should Application.Run() be called for the main presenter of a MVP WinForms app?

I'm learning to apply MVP to a simple WinForms app (only one form) in C# and encountered an issue while creating the main presenter in static void Main(). Is it a good idea to expose a View from the Presenter in order to supply it as a parameter to Application.Run()?
Currently, I've implemented an approach which allows me to not expose the View as a property of Presenter:
static void Main()
{
IView view = new View();
Model model = new Model();
Presenter presenter = new Presenter(view, model);
presenter.Start();
Application.Run();
}
The Start and Stop methods in Presenter:
public void Start()
{
view.Start();
}
public void Stop()
{
view.Stop();
}
The Start and Stop methods in View (a Windows Form):
public void Start()
{
this.Show();
}
public void Stop()
{
// only way to close a message loop called
// via Application.Run(); without a Form parameter
Application.Exit();
}
The Application.Exit() call seems like an inelegant way to close the Form (and the application). The other alternative would be to expose the View as a public property of the Presenter in order to call Application.Run() with a Form parameter.
static void Main()
{
IView view = new View();
Model model = new Model();
Presenter presenter = new Presenter(view, model);
Application.Run(presenter.View);
}
The Start and Stop methods in Presenter remain the same. An additional property is added to return the View as a Form:
public void Start()
{
view.Start();
}
public void Stop()
{
view.Stop();
}
// New property to return view as a Form for Application.Run(Form form);
public System.Windows.Form View
{
get { return view as Form(); }
}
The Start and Stop methods in View (a Windows Form) would then be written as below:
public void Start()
{
this.Show();
}
public void Stop()
{
this.Close();
}
Could anyone suggest which is the better approach and why? Or there even better ways to resolve this issue?
What about the following:
// view
public void StartApplication() // implements IView.StartApplication
{
Application.Run((Form)this);
}
// presenter
public void StartApplication()
{
view.StartApplication();
}
// main
static void Main()
{
IView view = new View();
Model model = new Model();
Presenter presenter = new Presenter(view, model);
presenter.StartApplication();
}
That way, you don't need to expose the view to the outside. In addition, the view and the presenter know that this view has been started as a "main form", which might be a useful piece of information.
I would go for the second approach.
You could also get rid of the extra property by simply casting view to form in the void Main, since you know it is a form anyway at that point (I see no reason to make it more generic than that since it just starts the winform app)
Application.Run(view as Form);
Things get a bit more complex if you allow more than one way to exit the application (e.g.: a menu item for exiting), or if you prevent closing of the application under certain conditions. In either case, the actual invocation of application closing should usually be invoked from presenter code rather than by simply closing the concrete view. This can be accomplished by using either the Application.Run() or Application.Run(ApplicationContext) overloads and exposing the application exit action via inversion of control.
The exact approach to registering and using the application exit action would depend on the IoC mechanism (e.g.: service locator and/or dependency injection) that you are using. Since you haven't mentioned what your current IoC approach might be, here's a sample that's independent of any particular IoC frameworks:
internal static class Program
{
[STAThread]
private static void Main()
{
ApplicationActions.ExitApplication = Application.Exit;
MainPresenter mainPresenter = new MainPresenter(new MainView(), new Model());
mainPresenter.Start();
Application.Run();
}
}
public static class ApplicationActions
{
public static Action ExitApplication { get; internal set; }
}
public class MainPresenter : Presenter
{
//...
public override void Stop()
{
base.Stop();
ApplicationActions.ExitApplication();
}
}
This basic approach could be adapted quite easily to your preferred IoC approach. For example, if you're using a service locator, you would probably want to consider removing at least the setter on the ApplicationActions.ExitApplication property, and storing the delegate in the service locator instead. If the ExitApplication getter were to remain, it would provide a simple façade to the service locator instance retriever. e.g.:
public static Action ExitApplication
{
get
{
return ServiceLocator.GetInstance<Action>("ExitApplication");
}
}
You could do it in a hundred ways to achieve the ultimate goal of separability of concerns. There is no hard and fast rule here, the basic idea is that presenter deals with presentation logic of the view, while the view has only the dumb knowledge of its own GUI specific classes and stuffs. Some ways I can think of (to broadly put):
1) View kick-starts things and let it decide its presenter. You start like, new View().Start();
// your reusable MVP framework project
public interface IPresenter<V>
{
V View { get; set; }
}
public interface IView<P>
{
P Presenter { get; }
}
public static class PresenterFactory
{
public static P Presenter<P>(this IView<P> view) where P : new()
{
var p = new P();
(p as dynamic).View = view;
return p;
}
}
// your presentation project
public interface IEmployeeView : IView<EmployeePresenter>
{
void OnSave(); // some view method
}
public class EmployeePresenter : IPresenter<IEmployeeView>
{
public IEmployeeView View { get; set; } // enforced
public void Save()
{
var employee = new EmployeeModel
{
Name = View.Bla // some UI element property on IEmployeeView interface
};
employee.Save();
}
}
// your view project
class EmployeeView : IEmployeeView
{
public EmployeePresenter Presenter { get; } // enforced
public EmployeeView()
{
Presenter = this.Presenter(); // type inference magic
}
public void OnSave()
{
Presenter.Save();
}
}
A variant of the above approach would be to enforce stronger generic constraint on view and presenter, but I dont think the complexity outweighs the benefits. Something like this:
// your reusable MVP framework project
public interface IPresenter<P, V> where P : IPresenter<P, V> where V : IView<P, V>
{
V View { get; set; }
}
public interface IView<P, V> where P : IPresenter<P, V> where V : IView<P, V>
{
P Presenter { get; }
}
public static class PresenterFactory
{
public static P Presenter<P, V>(this IView<P, V> view)
where P : IPresenter<P, V>, new() where V : IView<P, V>
{
return new P { View = (V)view };
}
}
// your presentation project
public interface IEmployeeView : IView<EmployeePresenter, IEmployeeView>
{
//...
}
public class EmployeePresenter : IPresenter<EmployeePresenter, IEmployeeView>
{
//...
}
Disadvantages
interacting between forms are less intuitive to me.
Steps involved:
implement IEmployeeView
instantiate presenter by calling PresenterFactory and passing this from the view constructor
ensure view events are wired to their corresponding presenter methods
start off, like new EmployeeView()....
2) Presenter kick-starts things and let it decide its view. You start like, new Presenter().Start();
In this approach presenter instantiates its own view (like approach 1) by means of some dependenchy injection or so, or view can be passed to presenter's constructor. E.g.
// your reusable MVP framework project
public abstract class IPresenter<V> // OK may be a better name here
{
protected V View { get; }
protected IPresenter()
{
View = ...; // dependenchy injection or some basic reflection, or pass in view to ctor
(View as dynamic).Presenter = this;
}
}
public interface IView<P>
{
P Presenter { get; set; }
}
// your presentation project
public interface IEmployeeView : IView<EmployeePresenter>
{
void OnSave(); // some view method
}
public class EmployeePresenter : IPresenter<IEmployeeView>
{
public void Save()
{
var employee = new EmployeeModel
{
Name = View.Bla // some UI element property on IEmployeedView interface
};
employee.Save();
}
}
// your view project
class EmployeeView : IEmployeeView
{
public EmployeePresenter Presenter { get; set; } // enforced
public void OnSave()
{
Presenter.Save();
}
}
Steps involved:
implement IEmployeeView
ensure view events are wired to their corresponding presenter methods
start off, like new EmployeePresenter(....
3) Event based, observer style
Here you could either encapsulate presenter in view (instantiate presenter in view) like approach 1 or encapsulate view in presenter (instantiate view in presenter) like approach 2 but in my experience latter will always be the cleaner design to work with. An e.g. of latter:
// your reusable MVP framework project
public abstract class IPresenter<V> where V : IView
{
protected V View { get; }
protected IPresenter()
{
View = ...; // dependenchy injection or some basic reflection, or pass in view to ctor
WireEvents();
}
protected abstract void WireEvents();
}
// your presentation project
public interface IEmployeeView : IView
{
// events helps in observing
event Action OnSave; // for e.g.
}
public class EmployeePresenter : IPresenter<IEmployeeView>
{
protected override void WireEvents()
{
View.OnSave += OnSave;
}
void OnSave()
{
var employee = new EmployeeModel
{
Name = View.Bla // some UI element property on IEmployeedView interface
};
employee.Save();
}
}
// your view project
class EmployeeView : IEmployeeView
{
public event Action OnSave;
void OnClicked(object sender, EventArgs e) // some event handler
{
OnSave();
}
}
// you kick off like new EmployeePresenter()....
Disadvantage:
You have to wire events on both view and presenter sides - double the work
Steps involved:
implement IEmployeeView
ensure iview events are called from view event handler methods
ensure iview event members are initialized from presenter
start off, like new EmployeePresenter()....
Limitations of language sometimes make design patterns more difficult. For e.g, had multiple inheritance been possible in C#, it was only a matter of having an abstract base view class with all the implementation details except UI specific components which could be then implemented by view class. No presenters, classic polymorphism and dead simple! Unfortunately this is not possible since most view classes in .NET (like Form of WinForms) already inherits from a super view class. So we have to implement an interface and go for composition. Also, C# doesnt let you have non-public members in an interface implementation, so we are forced to make all members specified in IEmployeeView public which breaks the natural encapsulation rules of the view class (i.e. other views in the view project can see details of EmployeeView irrelevant to them). Anyway, using power of C#'s extension methods a much simpler but very limited approach can be taken.
4) Extension method approach
This is just silly.
// your presentation project
public interface IEmployeeView
{
void OnSave(); // some view method
}
public static class EmployeePresenter // OK may need a better name
{
public void Save(this IEmployeeView view)
{
var employee = new EmployeeModel
{
Name = view.Bla // some UI element property on IEmployeedView interface
};
employee.Save();
}
}
// your view project
class EmployeeView : IEmployeeView
{
public void OnSave()
{
this.Save(); // that's it. power of extensions.
}
}
Disadvantages:
fairly unusable for anything remotely complex
Steps involved:
implement IEmployeeView
ensure this.... extension method is called from view events
kick off things by calling new View...
Of all 2 and 3 look better to me.

MVP dependency injection

using MVP, what is the normal order of construction and dependency injection.
normally you create a presenter for each view and pass the view into the presenter on constructor. But what if you have:
A Service that multiple views need to listen to events on.
Multiple views all pointing to the same data model cache.
can someone display a normal flow of info from a user click to data coming back in a service from a server.
Here is what I do:
First, I define theses interfaces:
public interface IView<TPresenter>
{
TPresenter Presenter { get; set; }
}
public interface IPresenter<TView, TPresenter>
where TView : IView<TPresenter>
where TPresenter : IPresenter<TView, TPresenter>
{
TView View { get; set; }
}
Then this abstract presenter class:
public abstract class AbstractPresenter<TView, TPresenter> : IPresenter<TView, TPresenter>
where TView : IView<TPresenter>
where TPresenter : class, IPresenter<TView, TPresenter>
{
protected TView view;
public TView View
{
get { return this.view; }
set
{
this.view = value;
this.view.Presenter = this as TPresenter;
}
}
}
The view is injected via a property, instead of the constructor, to allow the bi-directional affection in the setter. Notice that a safe cast is needed...
Then, my concrete presenter is something like :
public class MyPresenter : AbstractPresenter<IMyView, MyPresenter>
{
//...
}
Where IMyView implements IView. A concrete view type must exists (e.g. MyView), but it's the container that resolves it:
I register MyPresenter type as itself in the container, with a transient behavior.
I register MyView as an IMyView in the container with a transient behavior.
I then asks for a MyPresenter to the container.
Container instanciate a MyView
It instanciates a MyPresenter
It inject the view into the presenter through the AbstractPresenter.View property.
The setter code completes the bi-directional association
The container returns the couple Presenter/View
It allows you to inject other dependencies (services, repos) into both your view and your presenter. But in the scenario you described, I recommend you to inject services and caches into the presenter, instead of the view.
In WinForms, I prefer a simple approach. Usually you're dealing with a few UserControls on a design surface -- make these your view classes. .NET creates the control hierarchy for you (via InitializeComponent). If you use the Passive View pattern, each view then instantiates it's presenter. (You can do this either directly or by asking an IOC container.) Use constructor injection to pass a reference to the view's interface to the presenter's constructor. The presenter can then wire itself up to view events. Repeat the process for the model: the presenter instantiates a model and wires up to its events. (In this case you don't need the constructor injection since Passive View says the presenter keeps a reference to the model, not vice versa.)
The only nit I've found with this approach is properly managing lifetimes of the model and presenter. You want to keep the view as simple as possible, so you probably don't want it maintaining a reference to the presenter. However, that means you've got this presenter object hanging around with event handlers tied to your view. This setup prevents your view from being garbage collected. One solution is to have your view publish an event that indicates it's closing. The presenter would receive the event and remove both its model and view subscriptions. The objects in your web are now properly dereferenced and the garbage collector can go about its work.
You wind up with something like the following:
public interface IView
{
...
event Action SomeEvent;
event EventHandler Disposed;
...
}
// Note that the IView.Disposed event is implemented by the
// UserControl.Disposed event.
public class View : UserControl, IView
{
public event Action SomeEvent;
public View()
{
var presenter = new Presenter(this);
}
}
public interface IModel
{
...
event Action ModelChanged;
...
}
public class Model : IModel
{
...
public event Action ModelChanged;
...
}
public class Presenter
{
private IView MyView;
private IModel MyModel;
public Presenter(View view)
{
MyView = view;
MyView.SomeEvent += RespondToSomeEvent;
MyView.Disposed += ViewDisposed;
MyModel = new Model();
MyModel.ModelChanged += RespondToModelChanged;
}
// You could take this a step further by implementing IDisposable on the
// presenter and having View.Dispose() trigger Presenter.Dispose().
private void ViewDisposed(object sender, EventArgs e)
{
MyView.SomeEvent -= RespondToSomeEvent;
MyView.Disposed -= ViewDisposed;
MyView = null;
MyModel.Modelchanged -= RespondToModelChanged;
MyModel = null;
}
}
You can decouple this example a step further by using IOC and asking your IOC container for implementations of IModel (in the Presenter class) and IPresenter (in the View class).
interface IEmployee
{
int EmployeeId {get;}
string FirstName {get;}
string LastName {get;}
}
interface IEmployeeRepository
{
void SaveEmployee(IEmployee employee);
IEmployee GetEmployeeById(int employeeId);
IEmployee[] Employees { get; }
}
interface IEmployeeView
{
event Action<IEmployee> OnEmployeeSaved;
}
interface IEmployeeController
{
IEmployeeView View {get;}
IEmployeeRepository Repository {get;}
IEmployee[] Employees {get;}
}
partial class EmployeeView: UserControl, IEmployeeView
{
public EmployeeView()
{
InitComponent();
}
}
class EmployeeController:IEmployeeController
{
private IEmployeeView view;
private IEmployeeRepository repository;
public EmployeeController(IEmployeeView view, IEmployeeRepository repository)
{
this.repository = repository;
this.view = view;
this.view.OnEmployeeSaved+=new Action<IEmployee>(view_OnEmployeeSaved);
}
void view_OnEmployeeSaved(IEmployee employee)
{
repository.SaveEmployee(employee);
}
public IEmployeeView View
{
get
{
return view;
}
}
public IEmployeeRepository Repository
{
get
{
return repository;
}
}
public IEmployee[] Employees
{
get
{
return repository.Employees;
}
}
}
WinformsMVP is a very good MVP framework for Windows forms. You can easily inject an service across multiple views easily using this framework. This is a good article with a sample source code explains how to use the framework.

Categories

Resources