środa, 28 marca 2012

Notatki o Windows 8 Consumer Preview - odc.2

Postanowiłem, że wpisy tej serii będą krótsze w porównaniu do podobnych związanych z wersją Developer Preview, ale za to częstsze i poświęcone z reguły jednemu zagadnieniu. Dany temat będę przedstawiać z punktu widzenia różnych języków - z reguły to będą Java Script i C#, niekiedy będą wzmianki także o C++.

Ten odcinek będzie ogólnie o pisaniu aplikacji w różnych językach.

W pierwszej części zawarłem trochę uwag o Java Script. Moją uwagę przede wszystkim zwróciło doprecyzowanie niewspieranych funkcji (np. alert poza developmentem), dodatkowa funkcja done (obok funkcji then) w obiekcie Promise oraz fakt cachowania bytecodu w deployowanej aplikacji. Nie można się pokusić o zmodyfikowanie kodu w plikach .js w katalogu aplikacji, bo te zmiany nie wpłyną na zmianę zachowania. Trzeba ponownie zdeployować aplikację!

JS

The default.js file also declares that it runs in strict mode.

The answer for most HTML files is to provide a then or done function for the Promise returned by the WinJS.UI.processAll method. (For Page controls, you can use the ready function instead.)

You can use HtmlControl to display HTML from another page that doesn't contain interactivity (HtmlControl doesn't support the loading of JavaScript).

You can use an iframe to display content from another page. This is the least efficient way to incorporate content form another page, but it's your only option if you want to display an external web page.

In the Windows shell, the active app occupies a single window that fills most of the screen. You can't create new windows, and you can't resize or move existing windows. So window methods such as alert, prompt, open, moveBy, moveTo, resizeBy, and resizeTo don't work in Metro style apps using JavaScript. A page running in the local context can use window.close to quit the app, but should only use it in the case of an unrecoverable error. Pages running in the web context can't use window.close.

Note  The alert function doesn't work in a deployed app, but it does work when you run your app in the development environment (f.e for debug)

<p><a href="ms-appx:///page2.html">Go to page 2</a></p>

You can use the ApplicationContentUriRules section of the app's package manifest to give a page in the web context access to your system's geolocation devices (if your app has permission to access this functionality), as well as access to the clipboard and the ability to download files.

Bytecode caching

When an Metro style app using JavaScript is executed outside of the Microsoft Visual StudioMicrosoft Visual Studio 11 Express Beta for Windows 8 debugging environment, a number of performance optimizations occur. One important optimization is that all JavaScript files (files with a .js extension) included in the app package are converted into bytecode that the JavaScript engine can consume directly. Your app can load and execute the code in these files faster than it can load and execute unprocessed files, such as a JavaScript file on the web. This bytecode and a copy of the source code itself are stored in a single bytecode cache file with the package files. After the bytecode conversion completes, modifying the original source files has no effect on the app’s behavior until the app is re-deployed.

The list of the HTML and DOM APIs that behave differently or aren't supported for Metro style apps using JavaScript.

Although you can use Windows Library for JavaScript in the web context, some of its APIs work differently because the web context does not have access the Windows Runtime.

The most frequently used method on a promise object is then, which takes three parameters: a function to call when the promise completes successfully, a function to call when the promise completes with an error, and a function to provide progress information. In both the Windows Runtime and the Windows Library for JavaScript you can also use the done function, which takes the same parameters. The difference is that in the case of an error in processing, the then function returns a promise in the error state but does not throw an exception, while the done method throws an exception if an error function is not provided.

There are a couple of differences between then and done:

  • The then function returns a promise, but done doesn't return a value. You can use then functions as intermediate functions in a chain (myPromise().then().then().then()), but done must be the last function.

  • Unhandled exceptions in a then function are silently captured as part of the state of the promise, but unhandled exceptions in a done function are thrown. Both functions can handle exceptions that have been passed to them as part of the state of a promise.

The onerror event occurs whenever a runtime error is caught in a promise. You can use the error handler to set breakpoints while you're debugging or to provide general error handling such as error logging. But because this is a general error handling mechanism, you might not get much detail about the exact code or user input that caused the error.

WinJS.Promise.onerror = errorHandler

You can use promises in a number of different ways. You can chain promise operations by calling then or done on the promise that is returned by the previous then function. You can also track the progress of an operation and do error handling in the different functions you pass as parameters to then or done.

Use then for an intermediate stage of the operation (for example .then().then()), and done for the final stage of the operation (for example .then().then().done()). The differences between then and done are the following:

  • You can chain multiple then functions, because then returns a promise. You cannot chain more than one done method, because it returns undefined.

  • If you do not provide an error handler to done and the operation has an error, an exception is thrown to the event loop. This means that you cannot catch the exception inside a try/catch block, but you can catch it in window.onerror. If you do not provide an error handler to then and the operation has an error, it does not throw an exception but rather returns a promise in the error state.

  • You should prefer flat promise chains to nested ones. The formatting of promise chains makes them easier to read, and it's much easier to deal with errors in promise chains.

aAsync() .then(function () { return bAsync(); }) .then(function () { return cAsync(); }) .done(function () { finish(); });

Jeśli chodzi o C# to godne uwagi są z pewnością różnice w stosunku do WPF i Silverlight. Obecnie zostały doprecyzowane. Inny jest sposób dostępu do części pakietu, zmienione deklarowanie własnych przestrzeni w XAML, na poziomie tego języka deklaruje się obecnie typy prymitywne jak np. x:Double, przy obsłudze klawiatury zamiast PlatformKeyCode i Key mamy nowe podejście z VirtualKey i KeyStatus.

C#

  • Silverlight apps could either package application parts into the deployment package, as external parts, or download components on demand. A Metro style app has these choices too, but the APIs used to access the package parts are different. Where Silverlight uses Application.GetResourceStream, a Metro style app uses a more generalized model, where the installed package is just a storage folder. For example, you can call Package.InstalledLocation and then call a variety of StorageFolder APIs (most of which are async) in order to get any other packaged components.
  • Instead of using a clr-namespace:/assembly= qualifier set for code-to-XAML namespace references, you only use the using: qualifier. XAML namespaces no longer reference specific assemblies; all assembly qualification and inclusion is handled by the application model and project system.
  • Because you cannot map specific assemblies, some of the references that were made to mscorlib to support CLR primitives will no longer work. Instead, you can use the XAML language intrinsic types such as x:String. For more info, see XAML intrinsic data types. Also, consider that many of the strings that you stored before as x:String in a ResourceDictionary might better be stored as a string in the RESW resources file for the project.
  • XAML for Windows Runtime currently doesn't support custom markup extensions.
  • In most cases you can convert the relevant mouse event to PointerPressed, PointerReleased, PointerEntered or PointerExited.
  • Keys for key events do not have a PlatformKeyCode / Key separation. The reported key from event data uses a different enumeration, VirtualKey, and other key information is available as KeyStatus.
  • In order to best optimize the element set for the capabilities of the new graphics stack, we cut some APIs/concepts that would slow down rendering. Examples include OpacityMask, non-rectangular clips, non-symmetric corner radius on borders, custom easing functions, and bitmap effects.
  • However Metro style apps don't have what you might call "signature" controls like Silverlight's Pivot and Panorama. Instead, they have collection-ready controls such as SemanticZoom and FlipView. Additionally, the GridView is now a stand-alone control instead of a component that is used in a ListView.
  • Relative URIs are not supported, at least not at the level of the pure URI types. The .NET System.Uri might appear to give you a RelativeOrAbsolute choice in certain API calls, but in practice all such URIs are absolute, and are evaluated against concepts and locations such as the app package, user-selected locations, and so on. When specified in XAML, URIs often appear to be relative URIs, but these are processed and completed by the XAML parser before setting any runtime values. To reproduce this same behavior in code-behind, use the API FrameworkElement.BaseUri as the baseUri parameter value in the particular Uri constructor that combines a base URI with a relative URI.

W C++ zwraca uwagę klasa task do obsługi wywołań asynchronicznych poprzez funkcję then przypominająca rozwiązanie z JavaScript.

C++

In Visual C++, asynchronous programming is based on the task class, and its then member function. The syntax is similar to that of JavaScript promises. The task class class and its related types also provide the capability for cancellation and management of the thread context.

StorageFolder^ documentsFolder = KnownFolders::DocumentsLibrary;

task<StorageFile^> getFileTask(documentsFolder->GetFileAsync(fileName));

getFileTask.then([](StorageFile^ storageFileSample) ->IAsyncAction^ { return storageFileSample->DeleteAsync(); }).then([](void) { OutputDebugString(L"File deleted."); });

c.d.n

Brak komentarzy: