How to do code split in a typical GWT mvp project? - gwt

My app is a typical GWT application, it has a navigation bar, when click one bar item, the place will be changed and the app will find corresponding activity for that place(done in MasterActivityMapper), then call activity.start(). During the init of activities, the corresponding views were also created. When my app first starts, it will by default select the first navigation bar item.
public class MasterActivitiesMapper implements Activity
{
public Activity getActivity( Place place )
{
if(place equals place1)
{
Activity1 a1= new Activity1();
return a1;
}
else if(place equals place2)
{
Activity1 a2= new Activity2();
return a2;
}
else if(...)
{
....
}
}
}
My app works well except that the initial download size is too large, it will takes 10 seconds to load. I have to use code split the solve this problem.
I read the doc
https://developers.google.com/web-toolkit/doc/latest/DevGuideCodeSplitting
However still can not figure out where/how to split the code, could anybody has experience with this help?

Activity.start, being asynchronous by nature, seems like a good place to put a GWT.runAsync.
There's also the possibility of returning an activity async proxy from your ActivityMapper. See http://code.google.com/p/google-web-toolkit/issues/detail?id=5129 and https://gist.github.com/3038878 for some sample code.

Related

MVVM, wait cursor while opening "slow" page

I have MVVM application with multiple pages. My all pages have ReadCommand() bound with:
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding ReadCommand}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
This is my Read() command in ViewModel:
private void Read(object parameter)
{
HwDevice Device = new HwDevice();
this.Alarms = Device.Alarms; // this is slow (reading data from RS232 device)
Device.Dispose();
}
One page has slow data source and my application is frozen when this page is being loaded (about 5 seconds).
I want to set wait cursor on whole window, but I don't know how to do it in MVVM (Im MVVM newbie). Do I have to pass window reference by command parameter and set Wait cursor in command? If I should - how can I do it in XAML?
The problem is that the thread where you are going to execute your operation, is the same where your UI live. It's here that the BackgroundWorker come in handy.
BackgroundWorker bw = new BackgroundWorker();
bw.RunWorkerAsync += bw_DoWork;
bw.ProgressChanged += bw_ProgressChanged;
bw.RunWorkerCompleted += bw_WorkDone
The previous part was the declaration. Now you need to implement the events, but first modify Read method
private void Read(object parameter)
{
bw.RunWorkerAsync(parameter);
// put your logic here
}
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
object parameter = e.Argument;
}
Now that the logic is placed on another thread, you can use the progressChanged method to do various stuff. Like showing a progress bar to report the status, or simply enable or disable your wait cursor.
EDIT: You don't need to pass the bw to the UI. If you are using MVVM (like you should and you are doing) you can use bindings and event at your advantage, or implement an interface like this one. The point of the whole thing is that the UI is just "informed" that something on the background is going on, avoiding to freeze the main thread. You just need to decide how to display it. So it can be either using a wait cursor, or implementing a progress bar.

Show view from non-view/viewmodel in mvvmcross

What is the correct way to open a View in mvvmcross from a non-view? From within a viewmodel we would use ShowViewModel<>(..).
Specifically we are responding to a push notification opening the app (with a custom payload) which dictates a view that should be loaded.
We have a hackety workaround just for proof of concept, just wanted to get an idea of the correct MVX approach
I don't think there is a 'correct way' - I think it depends on your app and what you need it to do.
For some specific cases - e.g. ViewModel->ViewModel and AppStart - MvvmCross provides some convenient methods:
you can call ShowViewModel in MvxViewModel
the app start can be overridden to use a hint object - see https://speakerdeck.com/cirrious/appstart-in-mvvmcross
But overall, any class can request a ShowViewModel by calling:
var viewDispatcher = Mvx.Resolve<IMvxViewDispatcher>();
viewDispatcher.ShowViewModel(new MvxViewModelRequest(
viewModelType,
parameterBundle,
presentationBundle,
requestedBy));
Further, there is a base class - MvxNavigatingObject.cs - which can help with this (it's a base class of MvxViewModel and MvxAppStart) - so you can easily provide one or more services like INavigateMyselfService who's implementations inherit from MvxNavigatingObject.
public interface INavigateMyselfService
{
void GoWild(string side);
}
public class NavigateMyselfService
: MvxNavigatingObject
, INavigateMyselfService
{
public void GoWild(string side)
{
ShowViewModel<WildViewModel>(new { side = side });
}
}
http://forums.xamarin.com/discussion/4694/conditionally-call-registerappstart-with-mvvmcross
Check the above link and you will get idea
In my case,I want to launch the app from secondary tile.For this,I have to launch specific page for Secondary tile.
My Initial App Start view model is LoginViewModel and my custom app start view model is HomeViewModel.
I controlled this from App.cs (Core) to MyCustomAppStart class.
Refer the above link

JavaEE6 Conversation.end doesn't reset conversation.id to 1

Is the conversation.id not reset when conversation.end is called?
Scenario: I have an app that uses conversation scope in CRUD, so when I visit the list page it starts a conversation. Go to the detail and click back will call end conversation and begin conversation again. But while I'm at debug mode I found out that when conversation.end() is called conversation is set to null. Then when I reinvoke conversation.begin() conversation.id is not reset to 1 but rather the last value + 1. Is it correct to behave that way?
What's more puzzling is after logout and login again, the conversation.id pick up the last value + 1.
My environment: Jboss 7.1.3 using javaee-api.
protected void beginConversation() {
if (conversation.isTransient()) {
conversation.begin();
}
}
protected void endConversation() {
if (!conversation.isTransient()) {
conversation.end();
}
}
So basically I have a base entity (where the above code is defined.) extended by all the backing beans. When a list page is render it will call beginConversation. Clicking the back button in detail page will call endConversation.
Why should the conversation id be reset?
The best way to solve those questions is to directly having a look in the specification (in your case CDI 1.0), which states that the container has to generate an id for the conversation, but not how.
Check out this question, which states how it's done in WELD.

silverstripe dopublish function for ModelAdmin managed Pages

in the silverstripe backend I´m managing certain PageTypes via a ModelAdmin. That works fine so far, the only thing i can´t figure out is how to make a Page being "Published" when saving it.
Thats my code:
class ProjectPage extends Page {
public function onAfterWrite() {
$this->doPublish();
parent::onAfterWrite();
}
}
At the moment I can still see the ModelAdmin-created Pages in the Sitetree and I can see they are in Draft Mode. If I use the code above I get this error:
Maximum execution time of 30 seconds exceeded in
.../framework/model/DataList.php
Many thx,
Florian
the reason why you get "Maximum execution time exceeded" is because $this->doPublish(); calls $this->write(); which then calls $this->onAfterWrite();. And there you have your endless loop.
So doing this in onAfterWrite() or write() doesn't really work
you should just display the save & publish button instead of the save button
But I guess its easier said than done.
Well adding a button is actually just a few lines, but we also need a provide the functions that do what the button says it does.
This sounds like the perfect call for creating a new Module that allows proper handling of Pages in model admin. I have done this in SS2.4, and I have a pretty good idea of how to do it in SS3, but no time this week, poke me on the silverstripe irc channel on the weekend, maybe I have time on the weekend.
I found the same need/lack and I built a workaround that seems to work for me, maybe it can be useful.
public function onAfterWrite()
{
if(!$this->isPublished() || $this->getIsModifiedOnStage())
{
$this->publish('Stage', 'Live');
Controller::curr()->redirectBack();
}
parent::onAfterWrite();
}
Create a class that extends ModelAdmin and define an updateEditForm function to add a publish button to the actions in the GridFieldDetailForm component of the GridField.
public function updateEditForm($form) {
if ( ! singleton($this->owner->modelClass)->hasExtension('Versioned') ) return;
$gridField = $form->Fields()->fieldByName($this->owner->modelClass);
$gridField->getConfig()->getComponentByType('GridFieldDetailForm')->setItemEditFormCallback(function ($form) {
$form->Actions()->push(FormAction::create('doPublish', 'Save & Publish'));
});
}
Then create a class that extends GridFieldDetailForm_ItemRequest to provide an action handler for your publish button.
public function doPublish($data, $form) {
$return = $this->owner->doSave($data, $form);
$this->owner->record->publish('Stage', 'Live');
return $return;
}
Make sure the extensions are applied and you're done.
Or, you could just grab all the code you need from GitHub.

pause viewmodel process for user input

I've been looking at a view examples of the typical "raise dialog from viewmodel" problem, noting 3 main solutions:
use attached behaviors
use a mediator pattern
use a service
I'm getting a bit bogged down though and struggling to find a solution that easily fits into my problem space - which is a very simple file copy problem:
My viewmodel is processing a loop (copying a list of files)
When a file already exists at the destination I need to raise a modal dialog to get confirmation to replace
The vm needs to wait for and receive confirmation before continuing
The "modal dialog" is actually not a new window but a hidden overlay in my MainWindow, as per http://www.codeproject.com/KB/WPF/wpfmodaldialog.aspx (thanks Ronald!)
I'm mostly there but the biggest struggles I have are:
- how to pause the loop in the viewmodel while it waits for input
- how to get input back to the viewmodel within the loop so it can carry on
So far I'm leaning towards the service solution because it seems a direct method call with a return that the vm must wait for. However, it does mean the service needs to tie directly to the view in order to make an element visible?
If anyone can post some simple code that deals directly with this problem I (and the net) would be very happy! Thanks!
For example, you have a service called IDialogService with the following interface:
public interface IDialogService
{
bool ConfirmAction(string title, string confirmationText);
}
As you mentioned, in order for the service to be able to show the actual dialog it needs to have a reference to the view that will show the actual overlay element. But instead of directly referencing the view I prefer to reference it via an interface. Lets call it ICanShowDialog and it will have the following members:
public interface ICanShowDialog
{
void ShowDialog(object dialogContent);
void HideDialog();
}
This interface will be implemented by your view that owns the dialog overlay (e.g. your main window).
Now the interesting part: suspending the code execution while the dialog is shown. First of all, I would recommend you not to use overlay elements but use usual windows if possible. Then you will not have that problem. You can style the dialog window so it will look just like the overlay element.
Anyway, if you still want to use overlay elements then you can do the following trick to suspend the code execution:
Here is pseudo code of the ConfirmAction method of the IDialogService inteface:
public bool ConfirmAction(string title, string confirmationText)
{
ConfirmationDialogView dialogView = new ConfirmationDialogView(title, confirmationText);
DialogShower.ShowDialog(dialogView); // DialogShower is of type ICanShowDialog
while (!dialogView.ResultAvailable)
{
DispatcherUtils.DoEvents();
}
DialogShower.HideDialog();
return dialogView.Result;
}
Here is the code of DispatcherUtils.DoEvents() (that was taken from here: http://dedjo.blogspot.com/2007/08/how-to-doevents-in-wpf.html):
public static class DispatcherUtils
{
public static void DoEvents()
{
DispatcherFrame f = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(
DispatcherPriority.Background,
(SendOrPostCallback)delegate(object arg) {
DispatcherFrame fr = arg as DispatcherFrame;
fr.Continue=True;
}, f);
Dispatcher.PushFrame(frame);
}
}
But I must warn you. Using DoEvents can result in some subtle bugs caused by inner dispatcher loops.
As an alternative to suspending the code execution while a dialog is shown you can use callbacks:
public interface IDialogService
{
void ConfirmAction(string title, string confirmationText, Action<bool> dialogResultCallback);
}
But it will not be so convenient to use.