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 ...
}
}
Related
I have two identical views View1.xaml and View2.xaml and they both have a button button1 and a textfield textfield1. The idea is that when you press the button, the corresponding textfield is filled with some information. Both views use the same method for filling in the textfield (the views are literally identical in that sense).
My question is: how to write generic code using OOP principles and not break the MVVM pattern? My current way of performing this with RelayCommand:
The same code for ViewModel1 and ViewModel2:
public RelayCommand ButtonCommand { get; private set; }
#Constructor
ButtonCommand = new RelayCommand(ExecuteButtonCommand, CanExecuteButtonCommand);
#EndConstructor
private void ExecuteButtonCommand(object message)
{
//Some method to fill the corresponding textfield
}
private bool CanExecuteButtonCommand(object message)
{
return true;
}
Binding for the button in View1.xaml and View2.xaml:
<Button Command="{Binding Path=ButtonCommand, Mode=OneWay}" />
This is bad, because I have to write the same code for both ViewModels. I was trying to make a class ButtonCommand which inherits from RelayCommand, but because not every view will have this functionality, I can't achieve it using this method.
Rather than having a "Base" view model and two derived view models, have your two view models both use the same code defined elsewhere (ideally, both calling the same interface, injected with dependency injection).
This is the Composition over Inheritance principle.
When you're writing your tests, test that both view models call the interface, and test that the implementation of that interface does what it is supposed to do once.
This way, not only can you avoid writing your code twice, you can also avoid testing it twice, and it also allows you to follow other principles like the single responsibility principle.
This could be an way to go:
1 - Create a base viewmodel class:
public class YourBaseViewModel
{
public Object YourBaseProperty{get; set;}
public RelayCommand ButtonCommand { get; private set; }
private void ExecuteButtonCommand(object message)
{
//Some method to fill the corresponding textfield
}
private bool CanExecuteButtonCommand(object message)
{
return true;
}
}
2 - Inherit from the base viewmodel:
public class ViewModel1:YourBaseViewModel
{
// ....
}
public class ViewModel2:YourBaseViewModel
{
// ....
}
EDIT:
If you have another base class you could do:
public class YourBaseViewModel:YourReallyBaseViewModel
{
// ....
}
public class ViewModel1:YourBaseViewModel
{
// ....
}
public class ViewModel2:YourBaseViewModel
{
// ....
}
This is an XY problem. You're asking for a way to solve Y (not duplicate the same ButtonCommand but in actuality), your problem is X (you already have duplication in your code)
I have two identical views View1.xaml and View2.xaml
I'd like to add, that you've also stated you don't have only two identical views, there's more.
The best way to resolve this is to have a parent ParentViewModel that can construct the child ViewModels
So first, we'll need an interface for the child view model
IMyViewModel
public interface IMyViewModel
{
void Load();
}
Next, the implementation
MyViewModel
public class MyViewModel : ViewModelBase, IMyViewModel
{
public MainViewModel()
{
ButtonCommand = new RelayCommand(ExecuteButtonCommand, CanExecuteButtonCommand);
}
public RelayCommand ButtonCommand { get; private set; }
public void Load()
{
//Example load logic
InvalidateCommands();
}
private void InvalidateCommands()
{
ButtonCommand.RaiseCanExecuteChanged();
}
private void ExecuteButtonCommand(object message)
{
//Some method to fill the corresponding textfield
}
private bool CanExecuteButtonCommand(object message)
{
return true;
}
}
And lastly the ParentViewModel which has the responsibility of creating the view models. Please note, I did not tell it WHEN to create the ViewModels, I will leave that up to you.
Parent View Model
public class ParentViewModel : ViewModelBase
{
private Func<IMyViewModel> _myVmCreator;
public ParentViewModel(Func<IMyViewModel> myVmCreator)
{
_friendEditVmCreator = friendEditVmCreator;
}
public ObservableCollection<IMyViewModel> MyViewModels { get; private set; }
private IMyViewModel CreateAndLoadMyViewModel()
{
var myVm = _myVmCreator();
MyViewModels.Add(myVm);
myVm.Load();
return myVm;
}
}
This will allow you to create any number of MyViewModels, or any other type of ViewModel as long as it implements IMyViewModel.
The above example is derived from this course : https://www.pluralsight.com/courses/wpf-mvvm-test-driven-development-viewmodels
I highly recommend it.
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.
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.
In my N-Layered DDD architectured, all my ViewModel classes in application layer, implement following interface:
public interface IViewModel
{
ModelEntitySuperType ToModel();
}
So each ViewModel knows how to map back to the Domain Object(by implementing the ToModel() method).
[Updated]
Also I used CQRS pattern in my Application layer, so I defined the following generic abstract class for implementing Update command, you can see the usage of ToModel() method in followiing class(Handle method):
public abstract class UpdateCommandHandler<TCommandParameter, TViewModel, TEntity> : ICommandHandler<TCommandParameter>
where TCommandParameter : UpdateCommandParameter<TViewModel>
where TViewModel : class, IViewModel, new()
where TEntity : ModelEntitySuperType, IAggregateRoot, new()
{
private readonly IRepository<TEntity> _repository;
public string Code { get; set; }
protected UpdateCommandHandler(IRepository<TEntity> repository, string commandCode)
{
Code = commandCode;
_repository = repository;
}
public void Handle(TCommandParameter commandParameter)
{
var viewModel = commandParameter.ViewModelEntity;
var entity = viewModel.ToModel() as TEntity;
_repository.Update(entity);
}
}
Is it a correct way, that I put mapping logic into ViewModel objects?
What is better way to achieve this goal?
Usually I have mapping logic in layer which does mapping. Thus I keep both entities and view models unaware of each other and they have single responsibility. Responsibility of mapping between data types goes to mapping library (e.g. AutoMapper) or to extension methods.
E.g. if you want to convert Person entity to PersonViewModel, then with AutoMapper it will look like
var viewModel = Mapper.Map<PersonViewModel>(person);
Or you can have extension method
public static PersonViewModel ToViewModel(this Person person)
{
// create view model and map its properties manually
}
Usage will look like your current code, except you don't need to cast ModelEntitySuperType to PersonViewModel:
var viewModel = person.ToViewModel();
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.