Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Création et utilisation des contrôles dans les applications du Windows Store avec JavaScript
Télécharger l'exemple de code
Dans un précédent article, « Liaison de données dans une application du Windows Store avec JavaScript », nous avons exploré la bibliothèque Windows pour JavaScript (WinJS) et sa prise en charge de la liaison de données. L'utilisation de la liaison de donnée se produit souvent dans le contexte d'un contrôle. C'est pourquoi nous consacrons autant de temps à examiner en détail le contrôle ListView (vous pouvez consulter cet article à l'adresse msdn.microsoft.com/magazine/jj651576). Dans cet article, nous ferons une brève présentation des contrôles à la disposition des programmeurs JavaScript qui créent les applications du Windows Store. Si ces contrôles ne répondent pas à vos besoins, nous vous montrerons également comment créer vos propres contrôles.
Lorsque vous utilisez JavaScript pour créer des contrôles dans une application du Windows Store, les contrôles auxquels vous avez accès appartiennent à plusieurs familles :
- Éléments HTML5 : les éléments HTML5 sont des contrôles dans le sens où il s'agit de sections réutilisables d'interface utilisateur et de comportement (par exemple, <progress /> et <a />).
- Contrôles WinRT : il s'agit de contrôles exposés en tant que classes Windows Runtime (WinRT) projetées dans JavaScript, comme Windows.UI.Popups.PopupMenu.
- Contrôles WinJS : il s'agit de contrôles implémentés en tant que classes JavaScript, comme WinJS.UI.ListView.
- Styles CSS : CSS propose plusieurs styles qui vous permettent de présenter vos éléments de contenu comme s'il s'agissait de conteneurs de contrôle, par exemple, column-count: 4.
Dans cet article, nous allons nous concentrer sur les trois premières catégories de contrôles.
Éléments HTML5
Comme les applications du Windows Store créées avec JavaScript sont basées sur la technologie Web, tous les éléments HTML5 fonctionnent parfaitement, comme le montre la figure 1.
Figure 1. Contrôle HTML5 disponibles pour les applications du Windows Store créées avec JavaScript
Les détails relatifs aux éléments HTML5 sortent du cadre de cet article, mais nous vous recommandons de consulter votre documentation habituelle relative à HTML5 pour plus d'informations. De plus, l'exemple de code utilisé pour créer la figure 1 est fourni avec le téléchargement de code source accompagnant cet article.
Contrôles WinRT
Windows Runtime propose de nombreuses fonctionnalités dans toutes sortes de domaines, mais dans le cas des contrôles, il n'en fournit que deux :
- La boîte de message : message avec un titre facultatif.
- Le menu contextuel : menu limité à six éléments au maximum.
La boîte de message est appelée à l'aide de la fonction MessageDialog :
var popups = Windows.UI.Popups;
var mb = new popups.MessageDialog("and welcome to my message box!", "Hello!");
mb.showAsync();
La classe MessageDialog a une méthode showAsync qui retourne une promesse, comme toutes les autres opérations asynchrones dont dispose une application du Windows Store créée avec JavaScript. Dans ce cas, toutefois, nous ne tenons pas compte de la promesse, car le moment où une boîte de message disparaît nous importe souvent peu. La figure 2 illustre le résultat (en utilisant « MessageBox », qui est la terminologie précédemment utilisée pour MessageDialog).
Figure 2. Boîte de message WinRT
La classe PopupMenu est utilisée la même façon :
var popups = Windows.UI.Popups;
var menu = new popups.PopupMenu();
menu.commands.push(new popups.UICommand("one", null, 1));
menu.commands.push(new popups.UICommand("two", null, 2));
menu.showAsync({ x: 120, y: 360 }).done(function (e) {
// Do something with e.label and/or e.id
...
});
Dans cet exemple, après la création d'un objet PopupMenu, nous fournissons deux objets UICommand, comprenant chacun une étiquette, et des rappels et paramètres id facultatifs. Nous n'utilisons pas le rappel pour chacune des commandes dans cet exemple, car nous capturons le paramètre d'événement dans la méthode d'achèvement « done ». Un menu contextuel a l'apparence escomptée, comme illustré à figure 3.
Figure 3. Menu contextuel WinRT
N'oubliez pas qu'au moment de la rédaction de cet article, le menu contextuel est limité à six éléments seulement.
Contrôles WinJS
Bien que les contrôles HTML5 soient riches et variés, l'ensemble n'est pas extensible et ne le deviendra que lorsque le Consortium World Wide Web décidera d'ajouter une nouvelle balise d'élément et que les fournisseurs de navigateur décideront de l'implémenter. De la même manière, l'ensemble de contrôles WinRT n'est pas évolutif (bien que vous puissiez créer des composants Windows Runtime non basés sur une interface utilisateur). Pour l'ensemble évolutif de contrôles spécialement créés en pensant aux applications du Windows Store, la solution adaptée est l'ensemble fourni par WinJS.
Un contrôle WinJS est un contrôle implémenté en JavaScript qui offre une certaine signature dans la fonction de constructeur :
function MyControl(element,
options) {...}
L'argument de l'élément est l'élément Document Object Model (DOM) HTML qui est censé agir en tant qu'hôte pour le contenu du contrôle, souvent un div. L'argument des options est un objet JavaScript utilisé pour fournir des arguments de configuration en option, tels que la propriété ListView itemDataSource.
Pour voir un contrôle WinJS en action, prenons un div censé agir en tant qu'hôte d'un contrôle DatePicker :
<div id="datePickerDiv"></div>
Cela étant fait, nous pouvons créer un DatePicker facilement, comme ceci :
var datePicker = new WinJS.UI.DatePicker(datePickerDiv);
Le résultat est un contrôle DatePicker tout nouveau, comme illustré à la figure 4.
Figure 4. Résultat du contrôle DatePicker
Si nous souhaitons configurer un contrôle, nous pouvons transmettre un ensemble d'options :
var datePicker = new WinJS.UI.DatePicker(datePickerDiv, { current: "6/2/1969" });
Dans le cas de ce DatePicker, l'option utilisée nous permet de définir la date actuellement affichée, comme illustré à la figure 5.
Figure 5. Définition de la date actuellement affichée
Une fois qu'un contrôle est associé à votre élément HTML5, vous pouvez récupérer le contrôle à l'aide de la propriété winControl :
var datePicker = datePickerDiv.winControl; // Magical well-known property name
datePicker.current = "5/5/1995"; // Now we're talking to the control
Puis, une fois que vous avez le contrôle, vous pouvez revenir à l'élément HTML5 associé avec la propriété element :
var datePickerDiv = datePicker.element;
datePickerDiv.style.display = "none";
// Now we're talking to the HTML element
Outre le fait qu'il permet la création par programmation, chaque contrôle permet également la création déclarative via les attributs data-win-control et data-win-options, comme nous l'avons vu :
<div id="datePicker2"
data-win-control="WinJS.UI.DatePicker" data-win-options=
"{current: '6/2/1969'}" ></div>
L'attribut data-win-control est le nom de la fonction de constructeur à appeler. Comme dans la liaison de données, qui nécessite un appel à WinJS.Binding.processAll pour que les attributs data-win-bind soient analysés (voir notre article précédent), la propriété data-win-control nécessite un appel à WinJS.UI.processAll pour que l'analyse soit effectuée et que les contrôles soient créés. C'est pourquoi vous verrez un appel à WinJS.UI.processAll dans tout le code du modèle de projet généré.
La chaîne data-win-options est analysée comme une syntaxe d'initialisation d'objet JavaScript moins puissante. Par exemple, vous remarquerez qu'au lieu de définir l'option actuelle du contrôle DatePicker en créant un objet Date, nous avons directement passé la chaîne. C'est parce que l'analyseur d'options ne comprend pas le « nouveau » mot clé : il ne fonctionne qu'avec des données statiques. Cependant, comme le contrôle DatePicker et les autres contrôles WinJS s'attendent à être créés de manière déclarative, ils font des autorisations spéciales pour les limitations de l'analyseur d'options ; dans le cas du DatePicker, cela signifie recevoir une chaîne et l'analyser en tant qu'objet Date à votre place.
Chaque contrôle dispose d'un ensemble d'options différent. Reportez-vous à la documentation pour voir les options que propose chaque contrôle. La figure 6 présente une liste des contrôles WinJS prédéfinis.
Figure 6. Les contrôles WinJS
Nom | Description | Classe |
App Bar | Affiche les commandes de niveau application dans une barre d'outils | WinJS.UI.AppBar |
Date Picker | Affiche une interface graphique permettant de sélectionner une date | WinJS.UI.DatePicker |
Flip View | Affiche une collection d'éléments, un à la fois. | WinJS.UI.FlipView |
Flyout | Affiche en superposition un message au contenu arbitraire | WinJS.UI.Flyout |
List View | Affiche une collection d'éléments groupés ou non, dans une liste ou dans une grille | WinJS.UI.ListView |
Rating | Affiche une interface graphique permettant d'évaluer un élément (un film, par exemple) | WinJS.UI.Rating |
Semantic Zoom | Fournit une interface graphique permettant d'effectuer un zoom entre deux ListView, par exemple, un ListView groupé faisant un zoom arrière sur une liste de groupes | WinJS.UI.SemanticZoom |
Settings Flyout | Fournit une interface graphique pour la configuration des paramètres de l'application | WinJS.UI.SettingsFlyout |
Time Picker | Affiche une interface graphique permettant de sélectionner une heure | WinJS.UI.TimePicker |
Toggle Switch | Affiche une interface graphique permettant d'effectuer une sélection entre deux éléments | WinJS.UI.ToggleSwitch |
Tooltip (riche) | Affiche une info-bulle au contenu HTML arbitraire | WinJS.UI.Tooltip |
View Box | Fournit une zone de taille fixe ajustée de manière logique à l'espace disponible | WinJS.UI.ViewBox |
La Figure 7 montre les contrôles WinJS en action.
Figure 7. Contrôles WinJS en action
N'hésitez pas à combiner différents contrôles HTML5, WinRT et WinJS dans votre application du Windows Store.
Si vous ne trouvez pas le contrôle souhaité dans la liste proposée par HTML5, Windows Runtime ou WinJS, vous pouvez également créer votre propre contrôle.
Contrôles personnalisés
Comme nous l'avons indiqué, un contrôle WinJS n'est qu'une fonction qui fournit un constructeur qui a la forme suivante :
function MyControl(element, options) {...}
Créer un contrôle de ce type consiste à implémenter une fonction pour créer le HTML sous l'élément parent transmis comme premier argument et à utiliser l'objet options transmis comme second argument. Imaginez par exemple que vous souhaitiez créer un petit contrôle d'horloge, tel que celui de la figure 8.
Figure 8. Contrôle d'horloge personnalisé
Supposons que nous disposions d'un div destiné à contenir notre contrôle d'horloge :
<div id="clockControl1"></div>
Comme pour les contrôles WinJS intégrés, nous souhaitons pouvoir créer une instance d'un contrôle personnalisé, comme ceci :
var clock = new Samples.UI.ClockControl(clockControl1, { color: 'red' });
clock.color = 'red'; // Can set options as part of construction or later
Le nom choisi pour notre contrôle personnalisé est ClockControl dans l'espace de noms Samples.UI. Comme auparavant, créer le contrôle consiste à transmettre l'élément de conteneur (clockControl1) et un ensemble facultatif de paires nom/valeur pour les options. Si ensuite, au cours de la durée de vie du contrôle, nous souhaitons modifier l'une des options du contrôle, nous devons avoir la possibilité de le faire en définissant une valeur individuelle de propriété.
Nous souhaitons également pouvoir créer des contrôles personnalisés de manière déclarative :
<script src="/js/clockControl.js"></script>
...
<div id="clockControl2"
style="width: 200px; height: 200px;"
data-win-control="Samples.UI.ClockControl"
data-win-options="{color: 'red'}"> </div>
Dans le cadre de notre implémentation, nous souhaitons nous assurer que les propriétés d'élément et winControl sont définies, que les membres privés sont correctement marqués et que les événements sont gérés correctement. Lors de l'examen de l'implémentation du ClockControl, nous verrons comment WinJS nous aide à implémenter ces fonctionnalités.
Classe du contrôle En premier lieu, nous devons nous assurer que le ClockControl est dans l'espace de noms adéquat. Dans la plupart des langages modernes, le concept d'espace de noms est une manière de séparer les types, les fonctions et les valeurs en zones nommées distinctes afin d'éviter les collisions. Par exemple, si Microsoft fournit un type ClockControl dans WinJS 2.0, il sera dans l'espace de noms WinJS.UI, afin de ne pas entrer en collision avec Samples.UI. En JavaScript, un espace de noms est simplement un autre objet avec des constructeurs, des fonctions et des valeurs, que vous pouvez remplir ainsi :
// clockControl.js
(function () {
// The hard way
window.Samples = window.Samples || {};
window.Samples.UI = window.Samples.UI || {};
window.Samples.UI.ClockControl =
function(element, options) { ... };
})();
Ceci fonctionne parfaitement. Toutefois, définir des espaces de noms (et des espaces de noms imbriqués) est une opération tellement courante que WinJS (comme beaucoup de bibliothèques JavaScript) propose un raccourci :
// clockControl.js
(function () {
// The easy way
WinJS.Namespace.define("Samples.UI", {
ClockControl: function (element, options) { ... };
};
})();
La fonction de définition dans l'espace de noms WinJS.Namespace permet de définir un nouvel espace de noms, en gérant de façon adéquate l'analyse des noms séparés par des points à votre place. Le second argument est un objet permettant de définir les constructeurs, fonctions et valeurs que nous souhaitons exposer à partir de cet espace de noms, dans notre cas il s'agit simplement du constructeur ClockControl.
Méthodes et propriétés du contrôle Sur notre type ClockControl, nous souhaitons exposer des méthodes et des propriétés, telles que la propriété de couleur. Ces méthodes et ces propriétés peuvent être des instances ou être statiques, et peuvent être soit publiques, soit privées (du moins, aussi « privées » que JavaScript permet aux membres d'un objet de le devenir). Tous ces concepts sont pris en charge via l'utilisation correcte de la propriété de prototype du constructeur et de la méthode Object.defineProperties qui sont nouvelles en JavaScript. WinJS propose un raccourci pour ceci également, via la méthode define sur l'espace de noms WinJS.Class :
WinJS.Namespace.define("Samples.UI", {
ClockControl: WinJS.Class.define(
function (element, options) {...}, // ctor
{ // Properties and methods
color: "black",
width: { get: function () { ... } },
height: { get: function () { ... } },
radius: { get: function () { ... } },
_tick: function () { ... },
_drawFace: function () { ... },
_drawHand: function (radians, thickness, length) { ... },
})
});
La méthode WinJS.Class.define prend la fonction qui agit comme le constructeur, mais elle prend également l'ensemble des propriétés et des méthodes. La méthode define sait comment créer une propriété à partir des fonctions get et set fournies. De plus, elle sait que les propriétés et méthodes précédées d'un trait de soulignement (par exemple, _tick) sont conçues pour être « privées ». JavaScript ne prend pas réellement en charge les méthodes privées au sens traditionnel du terme ; cela signifie que nous pouvons donc toujours appeler la méthode _tick. Elles n'apparaissent toutefois pas dans Visual Studio 2012 IntelliSense ou dans les boucles for-in en JavaScript, ce qui est un moyen pratique d'indiquer qu'elles ne sont pas conçues pour être mises à la disposition du public.
Le constructeur définit les propriétés requises pour un contrôle WinJS, comme illustré à la figure 9.
Figure 9. Le constructeur définit les propriétés requises pour être un contrôle WinJS.
WinJS.Namespace.define("Samples.UI", {
ClockControl: WinJS.Class.define(function (element, options) {
// Set up well-known properties
element.winControl = this;
this.element = element;
// Parse the options; that is, the color option
WinJS.UI.setOptions(this, options);
// Create the drawing surface
var canvas = document.createElement("canvas");
element.appendChild(canvas);
this._ctx = canvas.getContext("2d");
// Draw the clock now and every second
setTimeout(this._tick.bind(this), 0);
setInterval(this._tick.bind(this), 1000);
},
...
});
Le constructeur définit tout d'abord les propriétés d'élément et winControl les plus connues, afin qu'un développeur puisse aller et venir entre l'élément HTML5 d'hébergement et le contrôle JavaScript.
Ensuite, le constructeur gère les options. Vous vous souvenez que les options peuvent être spécifiées sous la forme d'un ensemble de paires nom/valeur ou, à l'aide de l'attribut data-win-options HTML5, sous la forme d'une chaîne. WinJS gère l'analyse de la chaîne d'options dans un objet JavaScript : vous devez donc simplement gérer les paires nom/valeur. Si vous le voulez, vous pouvez extraire des propriétés individuelles, dans notre cas, la propriété de couleur, par exemple. Cependant, si vous disposez d'une longue liste d'options, la méthode setOptions dans l'espace de noms WinJS.UI parcourra toutes les propriétés dans l'objet options et les définira comme propriétés sur votre contrôle. Ainsi, les blocs de code suivants sont équivalents :
// Setting each property one at a time
myControl.one = "one";
myControl.two = 2;
// Setting all properties at once
WinJS.UI.setOptions(myControl, {
one: "one",
two: 2,
});
Une fois que les options du contrôle sont définies, le constructeur doit créer les éléments enfants de l'élément parent HTML5 dont il a besoin pour accomplir la tâche. Dans le cas du ClockControl, nous utilisons l'élément canvas HTML5 et un minuteur. L'implémentation de ce contrôle est du bon vieux code HTML et du JavaScript. Nous ne le montrerons donc pas ici (mais il est disponible dans le téléchargement de code accompagnant cet article).
Événements du contrôle Outre les méthodes et propriétés, un contrôle expose souvent des événements. Un événement est une notification provenant de votre contrôle qui indique que quelque chose d'intéressant s'est produit : par exemple, l'utilisateur a cliqué sur le contrôle ou le contrôle a atteint un état qui déclenche un type de comportement particulier dans votre programme. En vous basant sur l'exemple défini par le DOM HTML, vous souhaitez que des méthodes telles que addEventListener et removeEventListener permettent aux développeurs de s'abonner aux événements que votre contrôle expose, ainsi qu'aux propriétés onmyevent correspondantes.
Par exemple, si nous souhaitons exposer un événement de notre exemple ClockControl toutes les 5 secondes, nous nous attendons à pouvoir nous y abonner par programmation :
// Do something every 5 seconds
window.clockControl_fiveseconds = function (e) {
...
};
var clock = new Samples.UI.ClockControl(...);
// This style works
clock.onfiveseconds = clockControl_fiveseconds;
// This style works, too
clock.addEventListener("fiveseconds", clockControl_fiveseconds);
Declaratively, we’d like to be able to attach to custom events, too:
<!-- this style works, three -->
<div data-win-control="Samples.UI.ClockControl"
data-win-options="{color: 'white',
onfiveseconds: clockControl_fiveseconds}" ...>
</div>
L'activation de ces trois styles nécessite deux éléments : les méthodes permettant de gérer les abonnements d'événements (et pour distribuer les événements lorsqu'ils se produisent) et une propriété pour chaque événement. Ces deux éléments sont fournis par l'espace de noms WinJS.Class :
// clockControl.js
...
WinJS.Namespace.define("Samples.UI", {
ClockControl: WinJS.Class.define(...);
});
// Add event support to ClockControl
WinJS.Class.mix(Samples.UI.ClockControl,
WinJS.UI.DOMEventMixin);
WinJS.Class.mix(Samples.UI.ClockControl,
WinJS.Utilities.createEventProperties("fiveseconds"));
La méthode mix de WinJS.Class vous permet de combiner les propriétés et les méthodes fournies par des objets existants. Dans ce cas, DOMEventMixin de WinJS.UI fournit trois méthodes :
// base.js
var DOMEventMixin = {
addEventListener: function (type, listener, useCapture) {...},
dispatchEvent: function (type, eventProperties) {...},
removeEventListener: function (type, listener, useCapture) {...},
};
Une fois que nous avons combiné les méthodes de DOMEventMixin, nous pouvons créer les propriétés pour chaque événement personnalisé à l'aide de la méthode mix avec un objet créé par la méthode createEventProperties de WinJS.Utilities. Cette méthode produit un ensemble de méthodes d'événements pour chacun des noms d'événements délimités par des virgules que vous entrez, en ajoutant le préfixe « on ». Avec cet ensemble de propriétés et de méthodes fournies par ces deux appels à la méthode mix, nous avons complété notre contrôle personnalisé afin qu'il prenne en charge l'événement fiveseconds. Pour distribuer un événement de ce type au sein du contrôle, nous appelons la méthode dispatchEvent :
// clockControl.js
...
_tick: function () {
var now = new Date();
var sec = now.getSeconds();
...
// Fire the 5 second event
if (sec % 5 == 0) {
this.dispatchEvent("fiveseconds", { when: now });
}
},
...
Appeler dispatchEvent nécessite deux paramètres : le nom de l'événement et l'objet details facultatif disponible dans l'événement. Nous entrons une valeur « when » simple, mais JavaScript étant JavaScript, nous pourrions entrer ce que nous voulons. Accéder au détail de l'événement dans le gestionnaire consiste à extraire la valeur de détail de l'objet event :
// Do something every 5 seconds
window.clockControl_fiveseconds = function (e) {
var when = e.detail.when;
...
};
Les principes de la définition des contrôles WinJS que nous vous avons montrés (définition d'une classe dans un espace de noms, définition des propriétés d'élément et winControl, traitement de l'objet options, définition des propriétés et des méthodes, et définition et transmission des événements personnalisés) reprennent exactement les mêmes techniques que celles que l'équipe WinJS chez Microsoft a utilisées pour produire les contrôles WinJS. Pour en savoir plus sur la façon dont vos contrôles favoris ont été créés, lisez le fichier ui.js fourni avec WinJS.
Chris Sells est vice-président de la division Developer Tools de Telerik. Il est le coauteur du livre « Building Windows 8 Apps with JavaScript » (en anglais), (Addison-Wesley Professional, 2012), à partir duquel cet article a été adapté. Pour plus d'informations sur Chris Sells et ses différents projets, consultez l'adresse sellsbrothers.com.
Brandon Satrom est responsable de programme dans la division Kendo UI de Telerik. Il est le coauteur du livre « Building Windows 8 Apps with JavaScript » (en anglais), (Addison-Wesley Professional, 2012), à partir duquel cet article a été adapté. Vous pouvez le suivre sur Twitter à l'adresse twitter.com/BrandonSatrom.
Je remercie les experts techniques suivants d'avoir relu cet article : Chris Anderson, Jonathan Antoine, Michael Weinhardt, Shawn Wildermuth et Josh Williams