MVP, best practice for passing row events back to the presenter - gwt

I have a CellTable within a GWT MVP view and want to inform the presenter when certain actions are taken on a row. For example a popup menu is presented for a row, and an action (Delete/Edit/etc.) selected. There's obviously a SelectionModel that is available via HasData, but how would I use this to pass back the action 'action'.
Is there a standard interface (like HasData) that I could use to pass back to the Presenter?

Usually in GWT MVP View exposes an object that can register event handlers: usually thay come in form of HasXyxHandlers, like HasClickHandlers or HasChangeHandlers.
In case of CellTable it's named differently: SelectionModel. Just implement in View a method that returns it:
SelectionModel<YourClass> getSelectionModel();
then Presenter calls this method and registers itself:
final SelectionModel<YourClass> selectionModel = view.getSelectionModel();
selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
#Override
public void onSelectionChange(SelectionChangeEvent event) {
YourClass selectedObject = selectionModel.getSelectedObject();
// do something with selectedObject
}
});

Thinking about this more, I could be over engineering it. If I have one popup menu that I reuse in the view, and have the presenter listen to click events on the menu (rather than the CellList), then I can query the CellList selection model through within the handler for the button(s).

Related

Eclipse RCP Updating Toolbar and Menu Entries

I am using menu entries and toolbar buttons to link them to actions (AbstractHandler).
For example, I can connect to or disconnect from hardware. If I connect, there are menu and toolbar entries dependent on the connection state. They update after I click in the view or do another action within the view. For UX improvements it would be nice if they update after the action was executed.
Is there a way to update the view programmatically or do I have to implement this differently?
The connect handler is implemented very simple:
public class ConnectHandler extends AbstractHandler {
#Override
public Object execute(ExecutionEvent event) throws ExecutionException {
// Connect to hardware.
return null;
}
}
The menu and toolbar entries are defined in the plugin.xml.
I tried some stuff with the ICommandService and refreshElements, but was unsuccessful.

IInputSelectionProvider not considered by listeners of RCP SelectionService

I have a RCP application with different views. The views should interact with each other through the Eclipse SelectionService.
In view 1 I have added a SelectionListener with
getSite().getWorkbenchWindow().getSelectionService().addSelectionListener(this.listener);
In view 2 I have added a SelectionProvider with
getSite().setSelectionProvider(this);
To get this working, I implemented the methods from the IInputSelectionProvider in view 2. When I run my program, view 1s selection listener is not invoked. After debugging,
I found out that view 1 is not added in the list of listeners of view 2. In view 2 I have a method
private ListenerList listenersList = new ListenerList();
#Override
public void addSelectionChangedListener(ISelectionChangedListener iselectionchangedlistener) {
// TODO Auto-generated method stub
listenersList.add(iselectionchangedlistener);
}
which adds listeners to the IInputSelectionProvider. My question is: Who should call this method. My understanding is that Eclipse SelectionService should does this with
getSite().getWorkbenchWindow().getSelectionService().addSelectionListener(this.listener);
But it doesn't work. Do I have to fill the listenerList by myself? If yes, why do I have to use the SelectionService at all?
Or do I have to iterate through the list of listeners by calling any other method and not using the list at all? Because if I inspect the ISelectionService object
ISelectionService service = getSite().getWorkbenchWindow().getSelectionService();
I see all the listeners.
But they are not part of the listenerList above.
The addSelectionChangedListener is called every time a view gets activated and removed when a view is not longer active. This means: If View A is active and 'setSeletion' is called, all views which are listening are notified. If these views by themselves call 'setSelection' nothing happens. No notification is started.

Who should create view model instances in MvvmCross

Just to make it clear: I know MvvmCross is very flexible about where and how view models can be created. My question is more about proper separation of concerns, to simplify design of complex cross-platform applications.
Consider we have an app with customer list and customer details. On iPad and Surface the list and details are shown on the same page, but on smaller devices customer list and details for a selected customer are split between separate pages. So we have a PCL with CustomerListViewModel and CustomerDetailsViewModel. Now how should we manage view model lifetime from within the portable class library?
I originally did it using code in CustomerListViewModel implementation that looks like this:
public ICommand SelectCustomerCommand
{
get { return new MvxCommand(SelectCustomer); }
}
public void SelectCustomer()
{
if (formFactor == FormFactor.Phone)
{
ShowViewModel<CustomerDetailsViewModel>(new CustomerDetailsViewModel.NavObject(this.SelectedCustomer));
}
else
{
this.CustomerDetails = new CustomerDetailsViewModel(this.SelectedCustomer);
}
}
What is essential here is that we either call ShowViewModel that in turns asks a presenter to construct a CustomerDetailsViewModel object and render it in a new page or explicitly create an instance of CustomerDetailsViewModel and bind it to CustomerDetails.
After having seen episodes 32 and 42 of N+1 MvvmCross video series I am not quire sure this is the right way to do it. Of course it works, but should a view model care about instantiation details of other view model?
My second thought was to refactor this code and put this logic into a presenter, so I can simply write in CustomerListViewModel implementation:
public void SelectCustomer()
{
ShowViewModel<CustomerDetailsViewModel>(new CustomerDetailsViewModel.NavObject(this.SelectedCustomer));
}
... and presenter will do the rest inside the code triggered by ShowViewModel call. However, in the episode 42 it's shown how to control view model lifetime right from the associated view:
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
VisibleViewModel.IsVisible(false);
if (e.NavigationMode == NavigationMode.Back)
KillableViewModel.KillMe();
}
But if a view model lifetime is controlled by a presenter, shouldn't we try to place KillMe call inside presenter's logic? I know so small piece of code doesn't make much difference but couldn't this be an advantage to put it in presenter's class and reduce code-behind?
Definitely the ViewModel should not handle anything in regards to view (screen).
One quick idea I have is use a custom presenter which is able to create views based on the ShowViewModel<> requests.
The custom presenter is a view responsibility so you can test for screen orientation.
http://slodge.blogspot.co.uk/2013/06/presenter-roundup.html
For the second part of this question:
But if a view model lifetime is controlled by a presenter, shouldn't we try to place KillMe call inside presenter's logic? I know so small piece of code doesn't make much difference but couldn't this be an advantage to put it in presenter's class and reduce code-behind?
Currently view model presentation is orchestrated by the presenter - it gets ViewModelRequest objects and decides what to do with them.
However, it doesn't normally create the ViewModels - instead:
the presenter normally creates/shows a View
then the View creates (or locates) a ViewModel as part of the OnCreate, ViewDidLoad or OnNavigatedTo handling.
And so I don't think a ViewModel's lifetime is normally "controlled by a presenter" - instead I think a ViewModel is a "Model for a View" - so it's lifetime is "controlled by its view".
For the occasions where you need shutdown/dispose/killMe logic in your ViewModel, if you wanted to move that logic back inside the presenter - or into some other object - then you definitely could do so if you wanted to - it's your app and the app is king.
However, in these cases I suspect you would need the presenter to get some kind of notification from the View - as often the presenter doesn't know when Views are removed (when a modal is dismissed, when a Back button is pressed, when Android clears up stack views to save memory, etc).
As another way of thinking about this, if the presenter were renamed as INavigationService then what roles do you want that INavigationService to own within your app?

How are events implemented in MVP

I went through the link,
but there it was a bit difficult for me to understand the basic reason as to why
we shouldn't use view.getSaveButton().addClickHandler().... i.e to say why we should not have getter in our Display interface?? . What I understood from the video is that it is not a good practice to maintain views state information within the presentation, but sorry to say I didn't understood how is that gonna help us. ?
In that video its also mentioned that we should use setListeners() rather than addListeners(), that is to avoid more than one listener in the interface.
He says he is diverging from Rays understanding of MVP, with respect to not using HasClickHandlers() , please explain why ?
One of the reason why I couldnt understand the point could be that in that video there is lot of Google Wave specific code, It would had been easier for me to understand had he used a more generic and a more simpler code to make us understand his point.
Please pardon me if I have offended any one.
1) Presenter should not be depended from UI widgets - there is some reasons for it:
Separating of UI representation in Views and application logic in Presenter
Defined in interfaces behaviour of View and Presenter
Easy to write Unit-tests for presenter layer
Several views(desktop, mobile, e.t.c.) for one presenter
Simple set of interfaces named MVP allows us to separate this two layers:
// View interface
interface View extends AsWidget {
void setPresenter(Presenter presenter); // cross reference to presenter
interface Presenter { // presenter must extends from this interface
void onContactEditClick(); // callback from view handling in presenter without any UI code
}
}
// View realization (part)
public class ViewImpl extends Composite implements View {
#UiHandler('someButton') // or 'somelink', e.t.c.
void onContactEditClick(ClickEvent event) {
presenter.onContactEditClick();
}
}
Presenter is isolated from controls that firing events. It can be button, can be link, e.t.c. So it is possible to create several implementations of views(for desktop and mobile platforms for example) with a different set of UI controls in each view and use this views with a one presenter.
Google MVP
2) Listeners are related to UI controls. In my opinion, it is better to avoid usage of listeners between view and presenter via interface methods like in Point1 sample. In fact, Presenter interface inside of View interface is a better listener for all events from view.
3) The same. HasClickHanlers related to View layer and should be separated from presenter.

Showing another View from my current Viewmodel and closing a view from my viewmodel?

I have another view setup and ready and waiting with its viewmodel. My RelayCommand arrives in my "Current" viewmodel. What is the best way to show the new view from my current viewmodel?
I have been reading and it appears that I need to use the Messenger to send a message from my viewmodel to ??? my new viewmodel that is associated with my view I wish to show? But how would I show the View?
Also is there a way to support closing a view from a viewmodel? I wonder if mvvm-light brings anything extra to the table - ie.. Triggers to force the viewmodel to close the view?
In WPF, you have two ways (out of the box) for "showing"/"closing" views. The first, is simply, by showing a Window, or Dialog via the .Show() or .ShowDialog() methods, and they can be closed with the .Close() method. In this case, you can use the MVVMLight Messenger class as you mentioned to send the show/close messages to the view in a decoupled way. here's an example with "closing".
In the ViewModel:
CloseTheView()
{
Messenger.Default.Send(new CloseTheViewMessage);
}
in the code-behind of your view:
//Constructor
public TheView()
{
...
Messenger.Default.Register<CloseTheViewMessage>( () => this.Close() );
}
as you can see, this involves some code in the code-behind file, but it's no big deal, since it's just one line of functionality.
The second approach is to use the Navigation Framework (which is available for both WPF and Silverlight). You define a "Shell" which is the main Window (or UserControl), you put a frame inside of it, and you make your other views inherit from Page, and then initiate the navigation from your ViewModel using the instance of the NavigationService associated with Frame (or directly the one associated with the page itself).
Hope this helps :)