Same command for multiple views - c#

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.

Related

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 ...
}
}

Pass parameter to a constructor in the ViewModel

I am building a WPF browser application with MVVM pattern.
I have a first page (ConsultInvoice) with a dataGrid. When I double click on one of the row I want to navigate to another page (EditInvoice) passing the selected row in argument to my constructor.
I know if I want do things properly I should use a dependency injection, but I don't really see how to use it here.
How can I simply pass this constructor?
ConsultInvoiceViewModel
private Invoice _selected;
public Invoice Selected
{
get
{
return _selected;
}
set
{
_selected = value;
OnPropertyChanged("Selected");
}
}
private void Edit()
{
EditInvoiceViewModel editInvoice = new EditInvoiceViewModel(Selected);
/* doing something here*/
}
public ICommand EditCommand
{
get
{
return editCommand ?? (editCommand = new RelayCommand(p => this.Edit(), p => this.CanEdit()));
}
}
EditInvoiceViewModel
public class EditInvoiceViewModel : ViewModelBase
{
public Context ctx = new Context();
Invoice invoice;
PreInvoice preInvoice;
#region properties
private ObservableCollection<PreInvoice> collection;
public ObservableCollection<PreInvoice> Collection
{
get
{
return collection;
}
set
{
collection = value;
OnPropertyChanged("Collection");
}
}
#endregion
public EditInvoiceViewModel(Invoice inv)
{
/* do stuff*/
}
}
Basically you should avoid passing such parameters into the ViewModels constructor, as wiring it with Inversion of Control/Dependency Injection becomes a pain. While you can use Abstract Factory pattern to resolve objects with runtime parameters, it's imho not suitable for ViewModels.
Instead I always suggest using a form of navigation pattern, similar to how Microsoft's Patterns & Practices team has done with Prism. There you have an INavigationAware interface which your ViewModels can implement. It has 2 methods, NavigateTo and NavigateFrom.
And there is a navigation service. The navigation service will switch the views and before switching calling NavigateFrom in the current ViewModel (if it implements it. One can use it to check if data is saved and if necessary cancel the navigation. After the new View has been loaded and the ViewModel assigned to it, call NavigateTo in the newly navigated ViewModel.
Here you'd pass the parameters required for the ViewModel, in your case invoiceId. Try avoid passing whole models or complex objects. Use the invoiceid to fetch the invoice data and to populate your editing ViewModel.
A basinc implementation from my former answer (can be found here):
public interface INavigationService
{
// T is whatever your base ViewModel class is called
void NavigateTo<T>() where T ViewModel;
void NavigateToNewWindow<T>();
void NavigateToNewWindow<T>(object parameter);
void NavigateTo<T>(object parameter);
}
public class NavigationService : INavigationService
{
private IUnityContainer container;
public NavigationService(IUnityContainer container)
{
this.container = container;
}
public void NavigateToWindow<T>(object parameter) where T : IView
{
// configure your IoC container to resolve a View for a given ViewModel
// i.e. container.Register<IPlotView, PlotWindow>(); in your
// composition root
IView view = container.Resolve<T>();
Window window = view as Window;
if(window!=null)
window.Show();
INavigationAware nav = view as INavigationAware;
if(nav!= null)
nav.NavigatedTo(parameter);
}
}
// IPlotView is an empty interface, only used to be able to resolve
// the PlotWindow w/o needing to reference to it's concrete implementation as
// calling navigationService.NavigateToWindow<PlotWindow>(userId); would violate
// MVVM pattern, where navigationService.NavigateToWindow<IPlotWindow>(userId); doesn't. There are also other ways involving strings or naming
// convention, but this is out of scope for this answer. IView would
// just implement "object DataContext { get; set; }" property, which is already
// implemented Control objects
public class PlotWindow : Window, IView, IPlotView
{
}
public class PlotViewModel : ViewModel, INotifyPropertyChanged, INavigationAware
{
private int plotId;
public void NavigatedTo(object parameter) where T : IView
{
if(!parameter is int)
return; // Wrong parameter type passed
this.plotId = (int)parameter;
Task.Start( () => {
// load the data
PlotData = LoadPlot(plotId);
});
}
private Plot plotData;
public Plot PlotData {
get { return plotData; }
set
{
if(plotData != value)
{
plotData = value;
OnPropertyChanged("PlotData");
}
}
}
}
An example of the INavigationAware interface used in Prism can be found on the projects github repository.
This makes it easy to pass parameter and async load your data (where there isn't any clean way to do this via constructor, as you can't await an async operation inside the constructor without locking, and doing this kind of things in the constructor is very discouraged).

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 do I access a XAML object from a class other than main?

If I try "var mainpage new Mainpage()"
I will run the mainpage constructor and then all the fields in the XAML object will return to null. How to I access XAML objects in silverlight that are from a different class but part of the same namespace?
Let me explain by example. If you look at the first answer, here is what I am encountering
public class MyPage
{
MyPage()
{
// the constructor makes all the variables from the xaml null
}
public TextBox MyTextBox
{
get { return SomeTextBox; }
}
}
public class SomeOtherClass
{
private void SomeFunction()
{
var page = new MyPage(); // this makes the text empty
var sometext = page.MyTextBox.Text; // so sometext will be empty
}
}
So whatever the user imputs when the program first runs turns to null when I run SomeFunction.
What I am first going to try is to see if when SomeClass is created, the values are put into that class.
If that fails, I am going to try MVVM. I have seen the http://www.vimeo.com/8915487 video and I got the sample mvvm code
Here is the Model:
namespace SimpleMVVM.Model
{
public class SimpleModel
{
// super easy version
//public string SomeSimpleValue { get; set; }
private string _SomeSimpleValue = string.Empty;
// actually do something version...
public string SomeSimpleValue
{
get
{
return "some value";
}
set
{
_SomeSimpleValue = value;
}
}
}
}
here is the view:
and here is the viewmodel.cs
using Simple;
using SimpleMVVM.Model;
namespace SimpleMVVM.ViewModel
{
public class SimpleViewModel : SimpleViewModelBase
{
private SimpleModel MyModel = new SimpleModel();
public string SomeSimpleValue
{
get { return MyModel.SomeSimpleValue; }
set
{
if (MyModel.SomeSimpleValue != value)
{
MyModel.SomeSimpleValue = value;
RaisePropertyChanged("SomeSimpleValue");
}
}
}
}
}
Using this example, I am wondering if it will just as easy as injecting a ViewModel and then changing the bindings in the Model and the View.
Is MVVM really this easy?
There is one more. It is the viewmodel base class
using System.ComponentModel;
namespace Simple
{
public class SimpleViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string PropertyName)
{
var e = new PropertyChangedEventArgs(PropertyName);
PropertyChangedEventHandler changed = PropertyChanged;
if (changed != null) changed(this, e);
}
}
}
OK, so now the hard part. If I create a new class. How do I get the data from the viewmodel class?
First, let me get this rant out of the way: what you propose is very bad design. It fits the definition of smelly code.
If you insist on doing it this way, the "best" approach to take is to declare some public variables on your page that return the actual UI elements.
<UserControl x:Class="MyNamespace.MyPage" ...>
<Grid>
<TextBox x:Name="SomeTextBox" Width="100" />
</Grid>
</UserControl>
public class MyPage
{
public TextBox MyTextBox
{
get { return SomeTextBox; }
}
}
public class SomeOtherClass
{
private void SomeFunction()
{
var page = new MyPage();
page.MyTextBox.Text = "some text";
}
}
Of course the preferred method would be to use something like the MVVM pattern to implement binding from your window to its viewmodel, then you can just read the property values from the viewmodel, this way you avoid trying to touch any UI elements from a totally different class.
Another way to do it (without going the full MVVM route) is to inject the necessary values into the constructor of the control/page that you are instantiating, and from there you can assign them to the appropriate UI element properties. This is still smelly, but better than directly accessing the UI elements from the outside.

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.

Categories

Resources