how (multiple=true) presenter and view can be initialized with parameters using eventBus.addHandler? - gwt

With the Mvp4g architecture, (Only)one instance of the view (injected using #Presenter annotation)is associated with its presenter.
In my case, I have a EntityView with its Presenter EntityPresenter.
whenever user clicks on an Leaf node of a Navigator tree,
I add a new Tab into TabSet. And this new Tab will contain an EntityView.
So, I will have as many EntityView as many Tab in the TabSeT.
I have set multiple=true for EntityPresenter.
EntityView's constructor accepts one argument.
#Inject
public EntityView(final Record view) {
//some initialization
}
Question is, where I do (from another presenter):
EntityPresenter presenter = eventBus.addHandler(EntityPresenter.class);
I have one argument Record params which I want to pass to EntityView's constructor, how to do that?
and annotating constructor(accepting argument) with #Inject will inject EntityView to EntityPresenter ?

I suggest to use an EventHandler - that's a presenter without a view in mvp4g - which get an event showEntity(long key). In the onShowEntity(...) - method you can create the presenter with the statement:
EntityPresenter presenter = eventBus.addHandler(EntityPresenter.class);
With that reference of the instance, you can esaly set the key in the presenter.
But keep in mind, you have to manage your presenter instances by yourself, when using multiple=true.

Related

how to use eventBus.removeHandler in mvp4g?

I wanted to delete/clear all the instances of a presenter before firing an event. The documentation says to use eventBus.removeHandler(handler), I am not figure out how to get the handler object from the presenter class
Presenter has multiple=true attribute set.
If you have declared a presenter with "multiple="true"
#Presenter(view=OneView.class, multiple=true)
public class OnePresenter extends BasePresenter<IOneView, OneEventBus>{...}
you add the presenter to the eventbus by calling:
OnePresenter presenter = eventBus.addHandler(OnePresenter.class);
and remove the presenter by calling:
eventBus.removeHandler(presenter);
Here you will find the documentation:
https://github.com/FrankHossfeld/mvp4g/wiki/04.-Defining-presenters,-views-&-Services#multiple-presenter
In mvp4g you can easily activate and deactive presenters thanks to the activate/deactivate attribute of the #Event annotation. (https://github.com/FrankHossfeld/mvp4g/wiki/03.-Defining-EventBus#activatingdeactivating-presenters)
If you need to get the control just before a presenter handles an event, you can override the onBeforeEvent-method. (https://github.com/FrankHossfeld/mvp4g/wiki/04.-Defining-presenters,-views-&-Services#on-before-event)

How do I access the table wrapped by one Azure Mobile Services TableController from another TableController?

I have a new .Net back end Azure Mobile Service project with two TableController classes wrapping a table each and and I want to access one table from the other Controller. Am I supposed to instantiate one Controller from the other or just use the context object directly to access the data?
e.g.
RegistrationItemController wraps the RegistrationItem table
public class RegistrationItemController : TableController<RegistrationItem>
and UserController wraps the User table
public class UserController : TableController<User>
In my PostUser method on UserController am I supposed to instantiate an instance of RegistrationItemController and access it along the lines of:
public async Task<IHttpActionResult> PostUser(User item)
{
//look up RegistrationItem to validate this request
RegistrationItemController registrationController = new RegistrationItemController();
var registrationItem = registrationController.GetRegistrationItem(item.RegistrationId);
...
I say along the lines of as the above won't work as I can't call the protected Initialize method of RegistrationItemController which creates the context and creates the DomainManager.
Or am I going about this the wrong way and UserController should just its own context to access the RegistrationItem data directly?
Thanks
I had the exact same question. Apparently there is no way of accessing on TableController from the another one but there is a simple way of querying. In the Initialize method of each TableController an Entity Framework DbContext is created which can be saved as a member variable and then be used for querying every table exposed by the Entity Framework Context defined in your code.

Command class in Caliburn Micro

On my first project trying out Caliburn.Micro, I like a lot of the things :-)
One thing I miss (or havn't discovered yet) is how to separate the viewmodel and a command.
CM doesn't support ICommand, as it's way of doing things is superior. I'm sure it's true, so I would love a small push in the right direction to achieve this or perhaps discover a better way.
As I understand you have to put the "Execute" method and "CanExecute" property directly in the viewmodel, named to match the control in the view, to get the magic to work.
I would like to put the "Execute" and "CanExecute" in a different object that is property on the viewmodel and then CM would automatically bind to that object, using the control name and property names as usually.
Repost from the forum on Caliburn Micro, I didn't get any answers so I'm trying my luck here.
You should try to avoid invalidating the Law of Demeter. Therefore, on your view model you can have an execute method, and a CanExecute property (usually calculated), and these can call into the containing model where appropriate, e.g:
public void Save
{
// .. save logic
}
public bool CanSave
{
get
{
return this.model.CanSave ... and other logic etc.
}
}
You must remember to notify a change in the calculated property when the can save state changes, e.g:
public void CodeThatGetsRunWhenAPropertyOfTheModelChanges()
{
this.NotifyOfPropertyChanged(() => this.CanSave);
}
If you have e.g. a Button on your view with x:Name="Save", then Caliburn.Micro will automatically invoke your Save verb on the view model when the button is clicked, and will automatically enable and disable the button when the CanSave property value changes.
To avoid fat ViewModels you also need to avoid fat Views. Caliburn.Micro allows you to compose Views/ViewModels as described in Screens, Conductors and Composition.
The short version is, you can include a "DetailView" and "DetailViewModel" pair in a "MasterView"/"MasterViewModel" shell by defining a DetailViewModel-typed property in MasterViewModel and adding a ContentControl named after it in MasterView. Binding and actions work as usual, so you avoid both fat models/views and routing of commands.
Another option is to bind a MasterView element to a DetailViewModel property or action, by prepending the detail's property to the target's name. I can't find the specific URL yet, so the example is from memory.
Assuming you have the following classes:
public class MasterViewModel:Screen
{
public property DetailViewModel MyDetails{get;set;}
}
and
public class DetailViewModel:Screen
{
public property string SomeText{get;set;}
public void DoTheBoogie(){}
}
You can add a control in you MasterView named 'MyDetails_SomeText' to bind to the DetailViewModel.SomeText. You can also bind to DoTheBoogie the same way.
I prefer to create a separate View though, named DetailView and add a ContentControl named "MyDetails" in MasterView. This results in a cleaner and more modular design

Gin injecting in a shared (client server) object - "IsTreeItem"

I have an object that implements "IsTreeItem". The Object is displayed as a two level tree item. Each tree item is built with a check box.
I need to know when a check box is changing value - so i am listening to ValueChangedEvents.
The first problem is that the Tree built with such items only fires SelectionEvents. If selection is changing the check box the ValueChanged event is fired afterwards - so there is no way to listen to events inside "IsTreeItem" from Tree.
So i let my "IsTreeItem" fire its own element. So i (field)injected an EventBus and used it to fire the event if "ValueChanged".
The Problem is that my "IsTreeItem" is an Object sent from server (it is in shared package and serializable). The object is instantiated on server (EventBus is not ionjected) and "asTreeItem" is called on client.
Is there a way to inject the EventBus in the Method TreeItem asTreeItem() in some way? Or are there any other means to let some one outside know if a check box has changed its value.
GIN can do member injection on already created instances.
You have to create a method in your Ginjector interface that takes such an instance as argument, with a return type of void.
Note that because no reflection is done on the client, GIN will only inject fields and methods from the class used as the argument type (and its super-classes).
#GinModules(MyGinModule.class)
interface MyGinjector extends Ginjector {
…
void injectIsTreeItemMembers(IsTreeItem item);
}

Can I register a custom model binder somewhere other than Global.asax?

It would be handy to limit the scope of a custom model binder for just a specific controller action method or its entire controller. Hanselman wrote a sentence that implied alternative locations for custom model binder registration but never seemed to finish the thought:
You can either put this Custom Model Binder in charge of all your DateTimes by registering it in the Global.asax
Is it possible to make these registrations at a smaller scope of the controller system? If so, is there any reason to avoid doing so outside of the Global.asax MvcApplication (e.g., performance reasons)?
As I was closing the tabs I opened for this question that I hadn't reached before giving up, I found someone with an answer. You can assign a ModelBinderAttribute to your view models:
[ModelBinder(typeof(SomeEditorModelModelBinder))]
public class SomeEditorModel {
// display model goes here
}
public class SomeEditorModelModelBinder : DefaultModelBinder {
// custom model binder for said model goes here
}
While it wasn't quite what I was looking for, it is even more specific than registering it for a controller or controller method.
Update
Thanks to Levi's comment pointing out a much better solution. If you are consuming the object with a custom model binder in an MVC action method directly, you can simply decorate that method's parameter with the ModelBinder property.
public ActionResult SomeMethod([ModelBinder(typeof(SomeEditorModelBinder))]SomeEditorModel model) { ... }