M-V-VM Building an ERP-system – part 6 of N – customer interaction
Okay – so in post 5 we have managed to get and find data – now we need to be able to perform interactions with the data. We need an implementation of interface ICustomerDetailViewModel:
public class CustomerDetailViewModel : EntityViewModel<ICustomer, ICustomerRepository>, ICustomerDetailViewModel
{
private string _accountNumber;
private string _companyName;
public CustomerDetailViewModel(ICustomerRepository repository)
: base(repository) { }
protected override void ResetEntity()
{
_entity.AccountNumber = _accountNumber;
_entity.CompanyName = _companyName;}
protected override void CopyFromEntity()
{
_accountNumber = _entity.AccountNumber;
_companyName = _entity.CompanyName;
OnPropertyChanged(“AccountNumber”,”CompanyName”);}
public string AccountNumber
{
get { return _entity.AccountNumber; }
set
{
_entity.AccountNumber = value;
OnPropertyChanged(“AccountNumber”);}
}
public string CompanyName
{
get { return _entity.CompanyName; }
set
{
_entity.CompanyName = value;
OnPropertyChanged(“CompanyName”);}
}
}
public abstract class EntityViewModel<TEntity, TRepository> :NotifyPropertyChangedBase, IEntityViewModel<TEntity> where TEntity : class, IAggregateRoot where TRepository : IPersistRepository<TEntity>
{
protected TEntity _entity;
private readonly TRepository _repository;
private Action _onClose;
protected EntityViewModel(TRepository repository)
{
_repository = repository;
SaveChanges = new RelayCommand(DoSaveChanges, CanSave);
CancelChanges = new RelayCommand(DoCancelChanges);}
private void DoCancelChanges(object obj)
{
ResetEntity();
Close();}
protected abstract void ResetEntity();
public ICommand CancelChanges { get; private set; }
private string[] _validationErrors;
public string[] ValidationErrors
{
get { return _validationErrors; }}
public ICommand SaveChanges { get; private set; }
public void SetActionOnClose(Action action)
{
_onClose = action;}
public void SetEntity(TEntity entity)
{
_entity = entity;
CopyFromEntity();}
private bool CanSave(object obj)
{
if(_entity == null) return false;
var isValid = _entity.IsValid(out _validationErrors);
OnPropertyChanged(“ValidationErrors”);
return isValid;}
protected abstract void CopyFromEntity();
private void DoSaveChanges(object obj)
{
_repository.TrySave(_entity);
Close();}
private void Close()
{
_entity = null;
if (_onClose != null) _onClose();}
}
The CustomerDetailViewModel is pretty basic – it only handles user interactions and undo-functionality if the user cancels. There are a ton of ways to do undo (haha) – here I chose a very basic one which will not work for advanced entities. Here an alternative could be to reload it from the database or let the entity implement IEditableObject (often creating an exact clone to reflect the changes).
The base class is somewhat more interesting – a note on the implementation:
Why is there no IsValid method?
I’m relying on the SaveChanges command’s CanExecute – this will run everytime a property is changed in the view, and since this triggers the IsValid of the entity – these things happen automatically in the Command-structure of WPF.
You might think that it looks kinda simple for such an important task – but that is the whole point, I want my classes to be small and easy to comprehend. The inheritance adds complexity, but not a whole lot, and I do not need to explain a lot with comments or the like. The less lines of code, the less can go wrong – and the less will need to be maintained. Now all that is left for the solution to be able to handle customers is a few views and a few finishing touches.
This will be in parts 7 and 8.
About the series:
The solutions introduced here are not entry-level material. You should understand generics and basic patterns to fully utilize the material presented. The solution represents about 3 years of experience working with one ERP-solution. Some of the choices taken are heavily influenced from the large-scale solution and may seem overkill for the simple examples here, but the idea is to show the end-result of my experience and hopefully you as the reader will at least see a new way of doing things. The solution is built in .Net 4.0 with heavy use of WPF’s capabilities. Here you can find the source-code for the series. You are free to use this code for any purpose, but it is presented as-is with no guarantees. Enjoy!
Goblincave » M-V-VM Building an ERP-system – part 7 of N – Views said,
June 6, 2010 at 22:30
[...] – part 6 was ViewModels – now it is time for the eye-candy and unleashing the power of the ViewModels. [...]
Goblincave » M-V-VM Building an ERP-system – part 5 of N – CustomersViewModel said,
June 9, 2010 at 9:12
[...] part 6, I’ll look into the interactions with the [...]