Most of the MSDN WinJS app samples I've seen call WinJS.UI.processAll() after the app's activated event. I've also seen a number of non-MSDN tutorials that call WinJS.UI.processAll() after the DOMContentLoaded event.
Is there any practical reason to use one approach over the other?
It's a question of timing; personally I call it on DOMContentLoaded:
WinJS.Utilities.ready().done(function() {
WinJS.UI.processAll();
});
One of the primary reasons is that you can return the promise to the activation handler (the setPromise call you see in the templates), so that the splash screen is held a little longer until the WinJS.UI.processAll completes. This enables a better transition from splashscreen to completed content, without seeing partially constructed UI.
However, if you have UI that changes based on the activation type, you may want to delay this until you've constructed the DOM anyway. Since you need the activation type to make those differences, you'll need to call it after the activation event is raised.
Related
In WPF, for most UI events, we have PreviewX event as well. How come there is no such a thing in Universal Apps? Is the events system fundamentally different from that of WPF that there is no need for it?
Found the answer, the system has changed from bubbling and tunneling. Now it works with Routed Events. More information can be found here. Here is the important excerpt:
Earlier we said that setting Handled to true prevents most handlers from being called. But the AddHandler method provides a technique where you can attach a handler that is always invoked for the route, even if some other handler earlier in the route has set Handled to true in the shared event data.
So instead of adding the event handler as usual, you'll need to call AddHandler to add your "Preview" handler.
Something to note: the documentation does not say that these special handlers are executed before the regular ones, so it is not exactly the same as the PreviewX method.
Based on this article on MSDN: How To Determine When a Page Is Done Loading in WebBrowser Control, and from past discussions on StackOverflow, I would assume that in case of a document with multiple frames, the DocumentComplete event would fire multiple times, and the last time would be for the top level frame.
However, using the exact sample code from the above-mentioned MSDN link, I find that if there are multiple DocumentComplete events when doing a Navigate to a URL, the condition is satisfied in the following code the first time, not the last time as the article seems to indicate. Subsequent invokes of DocumentComplete seem to be for lower level frames, since the condition fails.
IUnknown* pUnk;
LPDISPATCH lpWBDisp;
HRESULT hr;
pUnk = m_webBrowser.GetControlUnknown();
ASSERT(pUnk);
hr = pUnk->QueryInterface(IID_IDispatch, (void**)&lpWBDisp);
ASSERT(SUCCEEDED(hr));
if (lpDisp == lpWBDisp )
{
// Top-level Window object, so document has been loaded
TRACE("Web document is finished downloading\n");
}
lpWBDisp->Release();
I am not sure why the behaviour I observe is exactly opposite of what it is supposed to be as per the documentation. Any pointers on this would be appreciated.
Background: I am using this code in a dialog-based VC++ / MFC application, and in the DocumentComplete event I want to get certain statistics when the document is fully loaded. So I was trying to use the above code to detect that a particular instance of DocumentComplete firing is when the page has fully loaded.
IMO, the most reliable way to get notified when the page has been fully loaded is to attach to window.onload DOM event for the top window object (IWebBrowser2::get_Document, IHTMLDocument2::get_parentWindow), when DocumentComplete is fired for the first time for a particular navigation. Then, onload event for the top web page will be fired when all inner frames have been loaded. This answer illustrates how it can be done in C# and this answer may help to get it done in C++.
The MSDN doc seems right to me: the last DISPID_DOCUMENTCOMPLETE is the one fired for the main frame.
I can't reproduce your problem for http://www.microsoft.com/ as that link gives me the final http://www.microsoft.com/fr-fr/default.aspx which is a single frame.
I don't like the way the sample code is testing for the Main Browser (equality of 2 IDispatch pointers). What I do is this:
QueryInterface the IDispatch for an IWebBrowser2
Make a true COM equality test, that is "comparing the IUnknown" from the 2 IWebBrower2 (I do it with the IsEqualObject method from the CComPtr template.
Could someone explain why the transitions (at least the default one - entrance) are not starting right away when a user clicks on a link (navigate) with Durandal?
In other words, do we need two mechanisms (loader animation + transition) to indicate that there is an action underway (ex. ajax call inside the activate method).
I'm sure there's a good reason, or maybe I just have to modify the entrance transition?
It seems like Durandal's transitions run once the activate function resolves. I asked a similar question where I enumerated some of the possible solutions that I found which worked for my situation specifically:
Manually animate away every view in its deactivate() and animate it back in via its viewAttached()
Bind the .page-host div's visibility to router.isNavigating (using a custom binding to handle the transition such as the fadeVisible example from the knockout site)
Manually subscribe to router.isNavigating and run custom logic when it changes
Hopefully this helps.
If you did not compress your entire application then the first process will be requirejs downloading the next amd module and then downloading the appropriate view.
The next step is durandal calling activate on your module. Activate if it returns a Deferred then it will wait for the deferred to complete.
Once activate is complete then the transition is called. The transition is responsible for swapping out the old view for the new one.
So, if its taking a while to kick off the transition its probably because its lagging in downloading your module and view.. or your activate method is taking a bit of time to finish.
One of the stated SpineJS goals is to make the entire UI non-blocking (i.e. display the change to the user, even though it might have not been updated successfully on the server side yet).
Can it be used in a standard "blocking" manner?
Yes it can. Look here under "callbacks":
http://spinejs.com/docs/ajax
You can basically block the UI at any point, and I do it for things that just can't be deferred to the server. Note that I don't even use the ajaxSucess() event, but just custom bindings for events. Here is an example use case in meta programming:
Bind 'clickHandlerFinish' event to clickHandlerFinishWork()
Bind 'click' event on button a to clickHandler()
User clicks on button a
clickHandler() gets fired
clickHandler disables the button and blocks the UI
clickHandler makes an AJAX call to the server to do work
(Remember UI is still blocked)
AJAX call finally returns, and fires the clickHandlerFinish() callback
clickHandlerFinish() unblocks the UI, re-enables the button, and presents the new changes
I've used this successfully on a few instances. Works great for me!
I have seen others with a similar issue but not quite what I was looking for. In the backgrounderworker class dowork event I create an instance of a new class and call one of it's function. Previously, I had this code in a windows.form.timer tick event and would pass a delegate in as one of the parameters which would allow the function and other functions it calls within the class to call a method on the form to update a datagrid on the GUI. Is there a way to do this within the dowork event? I need this because the function I call from dowork calls other functions and I want each of those functions to log information in the GUI datagrid.
The BackgroundWorker.ReportProgress() method was intended to do that. You implement the ProgressChanged event to update the UI, it will run on the main thread. You're not restricted to report just a progress percentage, you can pass any object as well to pass info to the event handler by using the overload that accepts the userState argument. Beware that you have to use proper locking if you do that.
Apart from ReportProgess mentioned in Hans' answer, you can alternatively use Control.Invoke on one of the UI elements to exeute code in the UI thread.
You can send progress data back to the UI thread, you will get an event for that on the UI thread, then you can update the screen. It is highly preferred that the objects you send back to the UI thread are immutable. Besides calling the ReportProgress and handling the event you need to opt-in by setting WorkerSupportsProgress property to true.