VII. Silverlight▲
SilverLight est un plugin pour internet.
Il permet de créer des applications complexes, mais aussi des pages plus simples.
Pour créer une application compilée, il faut installer un environnement de développement.
Tous les outils sont disponibles dans le Centre de développement Silverlight.
De plus, la version express de Visual Web Developper est gratuite.
Une application compilée génère un fichier XAP.
Nous n'allons pas détailler ces applications dans cet article.
Il est également possible d'écrire du code dans un fichier XAML, ce que nous allons développer.
Ce code sera interprété par le plugin Silverlight et ne nécessite rien de plus qu'un éditeur texte (et bien sûr un navigateur web pour le rendu).
Beaucoup de contrôles ne sont pas disponibles dans ce type de fichier.
Les contrôles d'un fichier XAP sont plus nombreux et complexes, mais ils ne sont pas (ou peu) exploitables en VBA.
Ils apparaissent cependant dans le plugin si on exécute le fichier XAP par exemple dans un WebBrowser.
Mais le dialogue entre VBA et les contrôles complexes du fichier XAP à travers le plugin Silverlight est très limité.
Nous allons voir quels contrôles sont disponibles en XAML dans la suite.
Ce sont des contrôles de dessin, d'affichage de texte, des images ou vidéos, et un contrôle de saisie de texte.
Consultez si besoin le forum Silverlight.
VII-A. Premier fichier XAML▲
Pour débuter : Tutoriel Silverlight
Créez un fichier texte avec l'extension .xaml : nommons-le silver1.xaml.
Ouvrez ce fichier avec un éditeur texte, par exemple WordPad.
Écrivez-y ce code :
<Canvas
xmlns
=
"http://schemas.microsoft.com/client/2007"
>
<Canvas>
Ce code est le minimum requis.
Le code XAML est sensible à la casse, c'est-à-dire que les minuscules et majuscules doivent être scrupuleusement respectées.
Canvas est une surface sur laquelle on va déposer nos autres contrôles : la racine du fichier est obligatoirement un canevas.
L'attribut xmlns est l'espace de noms utilisé par Silverlight.
Pour afficher le résultat, il faut créer une page HTML et y intégrer un pulgin Silverlight.
Un lien intéressant en français : Comment ajouter Silverlight à une page Web à l'aide de HTML
Créez un fichier texte avec l'extension .html : nommons-le silver1.html.
Ouvrez ce fichier avec un éditeur texte, par exemple WordPad.
Écrivez-y ce code :
<HTML>
<body>
<object id="SilverLight1" data="data:application/x-silverlight," type="application/x-silverlight-2"
width="100 %" height="100 %">
<param name="source" value="silver1.xaml"/>
<!-- Display installation image. -->
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50303.0"
style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376"
alt="Get Microsoft Silverlight"
style="border-style: none"/>
</a>
</object>
</body>
</HTML>
Ce code est du HTML classique.
On inclut dans des balises HTML, et dans le corps (body) du document, un objet Silverlight.
Cet objet a pour identifiant SilverLight1 : cet identifiant nous sera utile plus tard pour retrouver l'objet en VBA.
Les attributs data et type sont fixes quel que soit le fichier XAML utilisé.
On précise également la taille à 100 % du document. On pourrait y mettre des valeurs en pixels.
Dans l'objet, on ajoute les paramètres avec la balise param.
Le paramètre le plus important est la source qui précise où se situe le code.
Pour notre test, c'est le fichier silver1.xaml créé précédemment.
Ce fichier doit être dans le même répertoire que le fichier silver1.html, à moins de spécifier le chemin.
Au cas où le plugin n'est pas installé, il est utile d'informer l'utilisateur et de lui proposer de télécharger le plugin.
C'est le rôle du code qui suit le commentaire <!-- Display installation image. -->.
Si le plugin n'est pas installé, il s'affiche :
Si le plugin est installé, la page est vide...
Pour le voir, il suffit d'afficher la page silver1.html dans un navigateur web (double-cliquez sur le fichier suffit).
Nous l'intégrerons plus tard dans un contrôle WebBrowser.
L'affichage est vide car le canevas n'a pas de dimensions (ni de couleur de fond) et on n'y a pas ajouté de contrôles.
Nous allons ajouter un texte en haut du canevas :
<Canvas
Name
=
"rootcanvas"
xmlns
=
"http://schemas.microsoft.com/client/2007"
>
<TextBlock>
Premier écran<LineBreak/>
Silverlight</TextBlock>
</Canvas>
Un texte s'écrit avec la balise TextBlock.
Notez le <LineBreak/> qui définit un retour à la ligne.
Pour que les caractères accentués s'affichent correctement, le fichier doit être encodé en UTF-8.
Cet encodage peut être défini à la sauvegarde dans NotePad par exemple.
Pour écrire des caractères spéciaux : How to: Use Special Characters in XAML
Affichez la page HTML, le texte s'affiche en haut à gauche.
Il n'y a pas de couleur de fond, nous verrons par la suite pour colorer le fond.
Si rien ne s'affiche, il y a probablement une erreur : voyez le chapitre suivant.
VII-B. Gérer les erreurs▲
Il n'y a pas de gestion d'erreurs du code XAML par défaut.
Pour gérer les éventuelles erreurs, il faut ajouter un paramètre à l'objet SilverLight dans la page HTML.
<param name="onerror" value="OnErrorEventHandler" />
On ajoute le paramètre onerror qui a la valeur OnErrorEventHandler.
OnErrorEventHandler est une fonction à définir en JavaScript.
Ajoutons cette fonction au fichier HTML à partir des instructions de cette page : Comment : ajouter Silverlight à une page Web à l'aide de HTML.
Voici donc le code de la page silver1.html :
<HTML>
<script type="text/javascript">
function OnErrorEventHandler(sender, errorArgs)
{
// Create the error message to display.
var errorMsg = "Silverlight Error: \n\n";
// Specify error information common to all errors.
errorMsg += "Error Type: " + errorArgs.errorType + "\n";
errorMsg += "Error Message: " + errorArgs.errorMessage + "\n";
errorMsg += "Error Code: " + errorArgs.errorCode + "\n";
// Determine the type of error and add specific error information.
switch(errorArgs.errorType)
{
case "RuntimeError":
// Display properties specific to RuntimeErrorEventArgs.
if (errorArgs.lineNumber != 0)
{
errorMsg += "Line: " + errorArgs.lineNumber + "\n";
errorMsg += "Position: " + errorArgs.charPosition + "\n";
}
errorMsg += "MethodName: " + errorArgs.methodName + "\n";
break;
case "ParserError":
// Display properties specific to ParserErrorEventArgs.
errorMsg += "Xaml File: " + errorArgs.xamlFile + "\n";
errorMsg += "Xml Element: " + errorArgs.xmlElement + "\n";
errorMsg += "Xml Attribute: " + errorArgs.xmlAttribute + "\n";
errorMsg += "Line: " + errorArgs.lineNumber + "\n";
errorMsg += "Position: " + errorArgs.charPosition + "\n";
break;
default:
break;
}
// Display the error message.
alert(errorMsg);
}
</script>
<body>
<object id="SilverLight1" data="data:application/x-silverlight," type="application/x-silverlight-2"
width="100 %" height="100 %">
<param name="source" value="silver1.xaml"/>
<param name="onerror" value="OnErrorEventHandler" />
<param name="onresize" value="OnResizeEventHandler" />
<!-- Display installation image. -->
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50303.0"
style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376"
alt="Get Microsoft Silverlight"
style="border-style: none"/>
</a>
</object>
</body>
</HTML>
En cas d'erreur, le script affiche une boîte de message.
VII-C. Contrôles disponibles▲
Les contrôles, ainsi que leurs méthodes et propriétés disponibles, sont répertoriés sur cette page : JavaScript API for Silverlight.
Descendez dans la page jusqu'à Documentation for the JavaScript API.
Les contrôles sont présents (aux côtés d'autres objets) dans Objects Reference.
Nous allons utiliser dans la suite quelques-uns de ces contrôles.
VII-D. Adapater le canevas à la taille de la page▲
Tout d'abord nous avons remarqué qu'il n'y a pas de fond à la page Silverlight.
Effectivement le canevas a été défini sans taille ni couleur de fond.
Il n'est pas nécessaire de préciser une taille au canevas qui ne sert dans ce cas qu'à positionner les éléments.
Les éléments qui "débordent" du canevas sont quand même affichés.
Deux solutions pour ajouter une couleur de fond :
1 - soit ajouter un paramètre background à l'objet Silverlight de la page HTML.
<param name="background" value="yellow" />
Vous pouvez trouver les couleurs prédéfinies et le codage hexa des couleurs personnalisées par exemple ici : Color Table ;
2 - soit définir une couleur et une taille au canevas dans le fichier XAML :
<Canvas
Width
=
"300"
Height
=
"300"
Background
=
"#50FFFF00"
xmlns
=
"http://schemas.microsoft.com/client/2007"
>
J'ai ici défini une taille de 300x300 pixels, et une couleur de fond jaune (rouge+vert) de canal alpha (transparence) 50.
Retrouvez les couleurs prédéfinies et le codage hexa des couleurs personnalisées : Color, structure.
L'écran affiche la couleur de fond uniquement sur la taille du canevas. Le reste est la couleur de fond de la page internet.
Pour redimensionner le canevas à la taille de la page internet, nous allons écrire une petite fonction JavaScript.
Cette fonction sera appelée par le paramètre onresize de l'objet Silverlight dans la page HTML.
Ajoutez ce paramètre sous le paramètre "source".
<param name="onresize" value="OnResizeEventHandler" />
Écrivons ensuite, toujours dans la page silver1.html, la fonction JavaScript :
<HTML>
<script type="text/javascript">
function OnErrorEventHandler(sender, errorArgs)
{
[...]
}
function OnResizeEventHandler(sender, args)
{
sender.width = sender.gethost().content.actualwidth;
sender.height = sender.gethost().content.actualheight;
}
</script>
La fonction OnResizeEventHandler est à ajouter après la fonction OnErrorEventHandler, juste avant la balise de fin </script>.
Elle est assez simple :
- sender est le canevas racine de l'objet Silverlight ;
- gethost permet de remonter au plugin Silverlight : ne pas oublier les parenthèses pour indiquer que c'est une méthode ;
- On récupère alors la taille de l'objet et on l'affecte au canevas.
Pour que tout cela fonctionne, il faut que notre canevas soit nommé "rootcanvas" dans le fichier silver1.xaml :
<Canvas
Name
=
"rootcanvas"
Background
=
"#50FFFF00"
xmlns
=
"http://schemas.microsoft.com/client/2007"
>
Pas besoin de définir de dimensions ici, elles seront définies par JavaScript.
Pour parfaire le tout, on peut modifier les marges du corps du document HTML afin qu'il n'y ait plus d'entourage blanc.
<body topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0">
Si vous affichez la page silver1.html, vous obtenez le texte sur fond jaune qui remplit toute la page, même lorsqu'on redimensionne le navigateur.
En effet, l'objet Silverlight est défini avec des dimensions à 100 % : si on redimensionne le navigateur, l'objet Silverlight est redimensionné également.
Pour résumer, voici le code du fichier silver1.xaml :
<Canvas
Name
=
"rootcanvas"
Background
=
"#50FFFF00"
xmlns
=
"http://schemas.microsoft.com/client/2007"
>
<TextBlock>
Premier écran<LineBreak/>
Silverlight</TextBlock>
</Canvas>
Et voici le code du fichier silver1.html :
<HTML>
<script type="text/javascript">
function OnErrorEventHandler(sender, errorArgs)
{
// Create the error message to display.
var errorMsg = "Silverlight Error: \n\n";
// Specify error information common to all errors.
errorMsg += "Error Type: " + errorArgs.errorType + "\n";
errorMsg += "Error Message: " + errorArgs.errorMessage + "\n";
errorMsg += "Error Code: " + errorArgs.errorCode + "\n";
// Determine the type of error and add specific error information.
switch(errorArgs.errorType)
{
case "RuntimeError":
// Display properties specific to RuntimeErrorEventArgs.
if (errorArgs.lineNumber != 0)
{
errorMsg += "Line: " + errorArgs.lineNumber + "\n";
errorMsg += "Position: " + errorArgs.charPosition + "\n";
}
errorMsg += "MethodName: " + errorArgs.methodName + "\n";
break;
case "ParserError":
// Display properties specific to ParserErrorEventArgs.
errorMsg += "Xaml File: " + errorArgs.xamlFile + "\n";
errorMsg += "Xml Element: " + errorArgs.xmlElement + "\n";
errorMsg += "Xml Attribute: " + errorArgs.xmlAttribute + "\n";
errorMsg += "Line: " + errorArgs.lineNumber + "\n";
errorMsg += "Position: " + errorArgs.charPosition + "\n";
break;
default:
break;
}
// Display the error message.
alert(errorMsg);
}
function OnResizeEventHandler(sender, args)
{
sender.width = sender.gethost().content.actualwidth;
sender.height = sender.gethost().content.actualheight;
}
</script>
<body topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0">
<object id="SilverLight1" data="data:application/x-silverlight," type="application/x-silverlight-2"
width="100%" height="100%">
<param name="source" value="silver1.xaml"/>
<param name="onerror" value="OnErrorEventHandler" />
<param name="onresize" value="OnResizeEventHandler" />
<!-- Display installation image. -->
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50303.0"
style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376"
alt="Get Microsoft Silverlight"
style="border-style: none"/>
</a>
</object>
</body>
</HTML>
Cette page HTML est réutilisable à loisir : il suffit de modifier la source de l'objet Silverlight1.
Il faut bien sûr nommer le canevas "rootcanvas" pour que la fonction de redimensionnement fonctionne.
VII-E. Arranger les contrôles dans une grille▲
Cela ne vous a pas échappé, le texte n'est pas centré...
Pour le centrer, c'est plus compliqué qu'on pourrait l'imaginer.
Il y a bien une propriété TextAlignement :
<Canvas
Name
=
"rootcanvas"
Background
=
"#50FFFF00"
xmlns
=
"http://schemas.microsoft.com/client/2007"
>
<TextBlock
TextAlignment
=
"Center"
>
Premier écran<LineBreak/>
Silverlight
</TextBlock>
</Canvas>
Mais voici le résultat :
Le texte n'est pas centré sur le canevas, mais seulement sur sa plus grande ligne.
En effet, le texte est centré sur sa largeur, et sa largeur est déterminée lors de l'écriture du texte.
On voudrait définir sa largeur en fonction de celle du canevas qui le contient, mais on ne peut pas (du moins je ne sais pas).
C'est le contrôle Grid qui va nous sauver.
Nous allons créer une grille d'une seule colonne et de deux lignes.
La première ligne contiendra le texte de titre, et la deuxième ligne un canevas sur lequel nous poursuivrons.
Là où la grille nous sauve, c'est que les éléments que l'on place dans les cellules d'une grille occupent toute la cellule.
On dimensionnera bien sûr la grille pour qu'elle occupe toute la page, un peu comme nous l'avons fait avec le canevas.
Voici le nouveau code du fichier silver1.xaml :
<Canvas
Name
=
"rootcanvas"
Background
=
"#50FFFF00"
xmlns
=
"http://schemas.microsoft.com/client/2007"
>
<!-- La Grille -->
<Grid
Name
=
"rootgrid"
ShowGridLines
=
"True"
>
<!-- Définition des colonnes -->
<Grid.ColumnDefinitions>
<ColumnDefinition
Width
=
"*"
/>
</Grid.ColumnDefinitions>
<!-- Définition des lignes -->
<Grid.RowDefinitions>
<RowDefinition
Height
=
"Auto"
/>
<RowDefinition
Height
=
"*"
/>
</Grid.RowDefinitions>
<!-- Texte d'en-tête dans la première ligne -->
<TextBlock Grid.
Row
=
"0"
Grid.
Column
=
"0"
TextAlignment
=
"Center"
>
Premier écran<LineBreak/>
Silverlight
</TextBlock>
<!-- Canvas dans la deuxième ligne -->
<Canvas
Name
=
"secondcanvas"
Background
=
"#FFDDDD"
Grid.
Row
=
"1"
Grid.
Column
=
"0"
>
<!-- On ajoute d'autres contrôles ici -->
</Canvas>
</Grid>
</Canvas>
Nous avons nommé la grille rootgrid afin de la retrouver facilement par code.
Pour y voir plus clair, on affiche les lignes de la grille avec ShowGridLines="True".
Ensuite on définit les colonnes :
- il n'y a qu'une colonne : le * en largeur (Width) signifie que la colonne prend tout l'espace disponible.
Puis on définit les lignes :
- Première ligne pour l'en-tête : on ne définit pas de hauteur (Height) particulière, "Auto" signifie que la ligne prendra la taille de l'élément qu'elle contient.
Elle s'adaptera donc au texte que nous écrirons dedans.
- Deuxième ligne : le * en hauteur (Height) signifie que la ligne prend tout l'espace restant.
Et enfin on place nos éléments.
Pour chaque élément, il faut préciser la colonne et la ligne dans lesquelles on les place.
La première ligne et la première colonne commencent à l'indice 0.
Dans la première ligne on place notre texte centré.
Dans la deuxième ligne on place un canevas dans lequel on pourra mettre d'autres éléments.
Pour distinguer visuellement ce deuxième canevas, on a défini une couleur différente.
La grille ne va pas par défaut occuper toute la taille du canevas qui la contient.
On va la redimensionner dans la fonction JavaScript OnResizeEventHandler du fichier silver1.html.
function OnResizeEventHandler(sender, args)
{
sender.width = sender.gethost().content.actualwidth;
sender.height = sender.gethost().content.actualheight;
sender.findname("rootgrid").width = sender.gethost().content.actualwidth;
sender.findname("rootgrid").height = sender.gethost().content.actualheight;
}
Après avoir redimensionné le canevas racine, on redimensionne la grille nommée rootgrid.
Pour retrouver la grille, appelez FindName sur le sender (notre canevas).
Voici le résultat obtenu :
Le texte est enfin centré.
On voit bien en rose le deuxième canevas qui occupe toute sa cellule.
Si on redimensionne le navigateur, tout le contenu est redimensionné.
À noter : les lignes de la grille ne sont disponibles qu'en pointillés. Cela est prévu à des fins de débogage uniquement.
Pour utiliser d'autres types de traits, il faut mettre chacun des éléments dans un élément Border.
Par exemple, pour encadrer le deuxième canevas d'un trait bleu de deux pixels d'épaisseur :
<!-- Canevas dans la deuxième ligne -->
<Border
BorderThickness
=
"2"
BorderBrush
=
"Blue"
Grid.
Row
=
"1"
Grid.
Column
=
"0"
>
<Canvas
Name
=
"secondcanvas"
Background
=
"#FFDDDD"
>
<!-- On ajoute d'autres contrôles ici -->
</Canvas>
</Border>
C'est alors l'élément Border qui est positionné dans la grille. Il contient l'élément Canvas.
Un rappel des codes complets des fichiers avant de se lancer enfin avec VBA :
- le fichier sliver1.xaml :
<Canvas
Name
=
"rootcanvas"
Background
=
"#50FFFF00"
xmlns
=
"http://schemas.microsoft.com/client/2007"
>
<!-- La Grille -->
<Grid
Name
=
"rootgrid"
ShowGridLines
=
"False"
>
<!-- Définition des colonnes -->
<Grid.ColumnDefinitions>
<ColumnDefinition
Width
=
"*"
/>
</Grid.ColumnDefinitions>
<!-- Définition des lignes -->
<Grid.RowDefinitions>
<RowDefinition
Height
=
"Auto"
/>
<RowDefinition
Height
=
"*"
/>
</Grid.RowDefinitions>
<!-- Texte d'en-tête dans la première ligne -->
<TextBlock Grid.
Row
=
"0"
Grid.
Column
=
"0"
TextAlignment
=
"Center"
>
Premier écran<LineBreak/>
Silverlight
</TextBlock>
<!-- Canevas dans la deuxième ligne -->
<Border
BorderThickness
=
"2"
BorderBrush
=
"Blue"
Grid.
Row
=
"1"
Grid.
Column
=
"0"
>
<Canvas
Name
=
"secondcanvas"
Background
=
"#FFDDDD"
>
<!-- On ajoute d'autres contrôles ici -->
</Canvas>
</Border>
</Grid>
</Canvas>
- le fichier sliver1.html :
<HTML>
<script type="text/javascript">
function OnErrorEventHandler(sender, errorArgs)
{
// Create the error message to display.
var errorMsg = "Silverlight Error: \n\n";
// Specify error information common to all errors.
errorMsg += "Error Type: " + errorArgs.errorType + "\n";
errorMsg += "Error Message: " + errorArgs.errorMessage + "\n";
errorMsg += "Error Code: " + errorArgs.errorCode + "\n";
// Determine the type of error and add specific error information.
switch(errorArgs.errorType)
{
case "RuntimeError":
// Display properties specific to RuntimeErrorEventArgs.
if (errorArgs.lineNumber != 0)
{
errorMsg += "Line: " + errorArgs.lineNumber + "\n";
errorMsg += "Position: " + errorArgs.charPosition + "\n";
}
errorMsg += "MethodName: " + errorArgs.methodName + "\n";
break;
case "ParserError":
// Display properties specific to ParserErrorEventArgs.
errorMsg += "Xaml File: " + errorArgs.xamlFile + "\n";
errorMsg += "Xml Element: " + errorArgs.xmlElement + "\n";
errorMsg += "Xml Attribute: " + errorArgs.xmlAttribute + "\n";
errorMsg += "Line: " + errorArgs.lineNumber + "\n";
errorMsg += "Position: " + errorArgs.charPosition + "\n";
break;
default:
break;
}
// Display the error message.
alert(errorMsg);
}
function OnResizeEventHandler(sender, args)
{
sender.width = sender.gethost().content.actualwidth;
sender.height = sender.gethost().content.actualheight;
sender.findname("rootgrid").width = sender.gethost().content.actualwidth;
sender.findname("rootgrid").height = sender.gethost().content.actualheight;
}
</script>
<body topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0">
<object id="SilverLight1" data="data:application/x-silverlight," type="application/x-silverlight-2"
width="100%" height="100%">
<param name="source" value="silver1.xaml"/>
<param name="onerror" value="OnErrorEventHandler" />
<param name="onresize" value="OnResizeEventHandler" />
<!-- Display installation image. -->
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50303.0"
style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376"
alt="Get Microsoft Silverlight"
style="border-style: none"/>
</a>
</object>
</body>
</HTML>
VII-F. Intégrer la page SilverLight dans un WebBrowser▲
Pour ajouter un Webbrowser à un formulaire, je vous renvoie vers le chapitre III-B Intégrer un navigateur internet à l'application.
Il suffit à l'ouverture du formulaire de naviguer vers notre page sliver1.html
Me.ctlNav.Navigate
"C:\silver1.html"
Il faut préciser le chemin complet du fichier HTML.
Pour trouver le chemin de votre application, utilisez une de ces fonctions :
Application | Fonction |
---|---|
Access | CurrentProject.Path |
Excel | ThisWorkbook.Path |
Word | ThisDocument.Path |
PowerPoint | ThisPresentation.Path |
Pour Access, n'oubliez d'ajouter Object avant le navigate.
VII-G. Piloter la page SilverLight à partir de VBA▲
Nous allons dans ce chapitre utiliser VBA pour gérer l'objet Silverlight.
Silverlight n'étant pas du tout prévu pour VBA, cela ne va pas être si facile.
VII-G-1. La librairie AgControl Type Library▲
Nous pourrions être tentés d'utiliser une librairie.
Il y en a bien une : AgControl Type Library.
Si on la référence, on voit ensuite dans l'explorateur d'objet (F2) les classes de cette librairie (nommée XcpControlLib) :
Il n'y a en fait pas grand-chose à notre disposition.
- IXcpControl est l'interface pour l'objet Plugin.
- IXcpObject est l'interface pour un élément contenu dans le Plugin.
- Xcpcontrol est un objet d'automation (j'avoue : je ne sais pas à quoi il sert).
Il est intéressant de voir les propriétés et méthodes disponibles, mais les éléments IXcpObject ne possèdent même pas de propriétés.
Nous n'allons en fait même pas utiliser cette librairie peu utile.
De plus, si nous référençons une version 4.0 de cette librairie par exemple, l'application ne fonctionnera pas sur un poste équipé seulement de la version 3 de Silverlight.
Nous utiliserons des objets non typés, et cela nous facilitera en fait la tâche.
Sinon, comment appeler une méthode d'un objet IXcpObject si rien n'est disponible : on aurait un message d'erreur alors que des méthodes existent pour ces éléments.
VII-G-2. Atteindre le plugin Silverlight▲
On va chercher le plugin une fois la page chargée : dans l'événement DocumentComplete du navigateur.
Recherchez cet événement dans les listes déroulantes en haut du module de code du formulaire.
Private
Sub
ctlNav_DocumentComplete
(
ByVal
pDisp As
Object, URL As
Variant
)
End
Sub
- pDisp est l'objet WebBrowser.
- URL est l'adresse du document HTML.
Le plugin est un élément HTML. Il est possible de le retrouver dans le document (HTMLDocument) avec fonction getElementById.
Nous avons vu cette fonction au chapitre IV.
L'objet plugin nous sera utile à plusieurs endroits du code.
Nous ajoutons donc une déclaration en en-tête du module du formulaire.
Private
oSL As
Object
Comme expliqué au chapitre précédent, oSL n'a pas de type particulier. Ce sera en fait un XcpControl.
Une fois le document chargé, on récupère l'objet plugin :
Private
Sub
ctlNav_DocumentComplete
(
ByVal
pDisp As
Object, URL As
Variant
)
Set
oSL =
pDisp.Document.getElementById
(
"silverlight1"
).Object
End
Sub
silverlight1 est l'id de notre objet dans le fichier silver1.html.
On rajoute Object à la fin car getElementById renvoie un élément HTML qui contient le plugin dans cette propriété Object.
On le voit bien dans la fenêtre Variables locales, avec un point d'arrêt dans l'événement DocumentComplete :
- pDisp est un WebBrowser.
- Document est un HTMLDocument.
- le sixième élément est un HTMLObjectElement, on le récupère avec getElementById.
- object est un IXcpControl2.
On retrouve sur cet objet la source ("silver1.xaml") et la gestion d'erreur ("OnErrorEventHandler").
On remarque une propriété importante : IsLoaded.
Cette propriété vaut True lorsque le plugin est chargé.
VII-G-3. Lire la page Silverlight▲
On a donc récupéré un objet oSL.
Dans DocumentComplete, cet objet n'est pas encore chargé.
Si on place une boîte de message, on le voit bien :
Private
Sub
ctlNav_DocumentComplete
(
ByVal
pDisp As
Object, URL As
Variant
)
Set
oSL =
pDisp.Document.getElementById
(
"silverlight1"
).Object
MsgBox
oSL.IsLoaded
End
Sub
La boîte de message indique "Faux"...
Si on veut lire le contenu du plugin, il faut d'abord attendre qu'il soit chargé :
Private
Sub
ctlNav_DocumentComplete
(
ByVal
pDisp As
Object, URL As
Variant
)
Set
oSL =
pDisp.Document.getElementById
(
"silverlight1"
).Object
While
Not
oSL.IsLoaded
DoEvents ' indispensable pour ne pas tout bloquer
Wend
MsgBox
oSL.IsLoaded
End
Sub
La boîte de message indique "Vrai"... Le plugin est chargé.
Le contenu du plugin se trouve dans l'objet content dont vous trouverez les méthodes et propriétés ici : Silverlight Plug-in.
Les propriétés de cet objet ne sont pas directement accessibles en VBA.
Par exemple :
MsgBox
oSL.Content.ActualWidth
Renvoie une erreur : Utilisation incorrecte de Null.
Pour lire une propriété, il faut utiliser l'instruction CallByName :
MsgBox
CallByName
(
oSL.Content
, "ActualWidth"
, VbGet)
La boîte de message affiche alors la largeur en pixels.
On souhaite maintenant récupérer l'élément racine, c'est-à-dire le canevas nommé "rootcanvas".
dim
oRoot as
object
set
oRoot =
CallByName
(
oSL.Content
, "root"
, VbGet)
oRoot est alors un objet de type Canvas.
Pour rappel, les méthodes et propriétés des objets sont ici JavaScript API for Silverlight.
Pour afficher le nom de l'élément ("rootcanvas"), il suffit d'appeler sa propriété Name :
MsgBox
CallByName
(
oRoot, "Name"
, VbGet)
Pour de nombreux objets, on a des méthodes GetValue et SetValue qui sont plus simples que CallByName :
MsgBox
oRoot.getvalue
(
"Name"
)
Si vous souhaitez connaître le type d'un objet, appelez la méthode toString :
MsgBox
oRoot.toString
Pour la racine toString renvoie Canvas.
On peut aussi, en débogage, survoler l'objet oRoot. L'info-bulle nous indique la même information.
Maintenant pour obtenir les éléments contenus dans ce canevas, utilisez la propriété Children.
Chidren renvoie une collection.
On peut récupérer le nombre d'éléments avec Count.
GetItem permet alors de récupérer un élément par son indice (débute à 0).
Si vous utilisez une variable, il sera peut-être nécessaire de convertir l'indice en entier avec CInt.
Dim
oRoot As
Object
Dim
oChildren As
Object
Set
oRoot =
CallByName
(
oSL.Content
, "root"
, VbGet)
Set
oChildren =
oRoot.getvalue
(
"Children"
)
MsgBox
"Nombre d'éléments dans le canevas racine : "
&
oChildren.getvalue
(
"Count"
)
MsgBox
"Nom du premier élément : "
&
oChildren.GetItem
(
0
).getvalue
(
"Name"
)
Il n'y a qu'un élément dans le canevas racine, c'est la grille "rootgrid".
On peut parcourir ainsi le contenu niveau par niveau.
Un exemple avec With :
' recherche la racine du plugin = canevas rootcanvas
With
CallByName
(
oSL.Content
, "root"
, VbGet)
' obtient la collection d'éléments du canevas
With
.getvalue
(
"children"
)
' Premier élément = rootgrid
With
.GetItem
(
0
)
' obtient la collection d'éléments de la grille
With
.getvalue
(
"children"
)
' Deuxième élément de la grille = border
With
.GetItem
(
1
)
' Element du border (il n'y en a qu'un)
With
.getvalue
(
"child"
)
' C'est le canevas secondcanvas
MsgBox
.getvalue
(
"name"
)
End
With
End
With
End
With
End
With
End
With
End
With
Si l'élément est nommé, on peut y accéder directement avec findName :
With
oSL.Content.findName
(
"secondcanvas"
)
MsgBox
.getvalue
(
"ActualWidth"
)
End
With
findName peut également être utilisé sur un élément pour rechercher à l'intérieur de celui-ci.
VII-G-4. Modifier la page Silverlight▲
Nous allons modifier le titre de la page.
Pour nous faciliter la tâche, nommons le TextBlock qui contient le titre dans le fichier silver1.xaml :
<!-- Texte d'en-tête dans la première ligne -->
<TextBlock
Name
=
"titre"
Grid.
Row
=
"0"
Grid.
Column
=
"0"
TextAlignment
=
"Center"
>
Premier écran<LineBreak/>
Silverlight
</TextBlock>
On peut ainsi le retrouver facilement avec findName.
Dim
oTitre As
Object
Set
oTitre =
oSL.Content.findName
(
"titre"
)
Pour modifier une propriété, c'est facile. Il suffit d'utiliser SetValue :
oTitre.SetValue
"text"
, "Mon Nouveau Titre"
oTitre.SetValue
"Foreground"
, "red"
oTitre.SetValue
"FontSize"
, 24
Le texte du titre est alors modifié, en rouge, et de taille 24 pixels.
VII-G-5. Ajouter dynamiquement un élément à la page Silverlight▲
Nous allons ici voir comment ajouter un élément à la page déjà chargée.
On continue avec les mêmes fichiers silver1.html et silver1.xaml.
Le fichier HTML est chargé dans un WebBrowser comme vu précédemment.
Et on attend dans DocumentComplete le chargement du plugin :
Private
Sub
ctlNav_DocumentComplete
(
ByVal
pDisp As
Object, URL As
Variant
)
Set
oSL =
pDisp.Document.getElementById
(
"silverlight1"
).Object
While
Not
oSL.IsLoaded
DoEvents ' indispensable pour ne pas tout bloquer
Wend
' On écrira la suite du code ici
End
Sub
On souhaite ajouter en VBA un texte au canevas "secondcanvas".
Commençons par écrire le code XAML de l'élément à ajouter.
On ajoute un simple TextBlock :
Dim
sxaml As
String
sxaml =
"<TextBlock>Texte ajouté</TextBlock>"
Pour créer un élément, il faut utiliser la méthode CreateFromXaml de l'objet Content du plugin.
On aurait aimé pouvoir écrire :
set
oElement =
oSL.Content.CreateFromXAML
(
sxaml)
Mais ce code provoque une erreur.
La seule solution que j'ai trouvée est de faire la création de l'élément en JavaScript.
Voici une petite fonction à ajouter dans la balise script du fichier silver1.html.
function AddElement(sxaml,sobject,sname,position) {
// objet plugin
var plugin = document.getElementById(sobject);
// création du nouvel élément
var element = plugin.content.CreateFromXaml(sxaml);
// Ajout de l'élément
if (position==-1)
// Ajout à la fin
{ plugin.content.FindName(sname).children.add (element); }
else
// Ajout avec position
{ plugin.content.FindName(sname).children.insert (position,element); }
}
Cette fonction demande en paramètres :
- sxaml : le code XAML de l'élément à ajouter.
- sobject : le nom de l'objet Silverlight (Silverlight1 pour notre exemple).
- sname : le nom de l'objet dans lequel on ajoute l'élément.
- position : la position à laquelle ajouter l'élément. La position commence à l'indice 0, on utilise -1 pour ne pas indiquer de position.
La méthode add de la collection children ajoute un élément à la fin.
La méthode insert insère un élément à une position donnée.
Cette fonction peut être appelée en VBA ainsi :
pDisp.Document.parentWindow.execscript
"AddElement('"
&
sxaml &
"','SilverLight1','secondcanvas',-1)"
La méthode execscript de la fenêtre (parentWindow) du document permet d'exécuter du JavaScript.
La limitation est que tout doit être écrit dans une seule chaîne de caractères, y compris les paramètres.
C'est pour cela que les paramètres ne sont pas des objets (ce qui nous aurait simplifier la tâche).
Notez que execscript ne retourne pas de valeur.
Les chaînes de caractères sont encadrées par des simples quotes (').
Pour inclure ce caractère dans le XAML, utilisez "\'". Par exemple :
sxaml =
"<TextBlock>J\'ajoute un texte</TextBlock>"
Les sauts de ligne (vbCrLf) provoquent également une erreur.
Il est souvent plus facile de créer d'abord l'élément puis de mettre à jour ses propriétés :
Dim
sxaml As
String
sxaml =
"<TextBlock/>"
pDisp.Document.parentWindow.execscript
"AddElement('"
&
sxaml &
"','SilverLight1','secondcanvas',-1)"
With
oSL.content.findname
(
"secondcanvas"
).getvalue
(
"Children"
).getitem
(
0
)
.SetValue
"text"
, "J'ajoute du texte"
&
vbCrLf
&
"avec un saut de ligne"
End
With
De cette manière, pas de problème pour ajouter des quotes (') ou des sauts de ligne (vbCrLf).
Pour nous faciliter la tâche, on peut créer une fonction VBA :
'------------------------------------------------------------------------------
' Insère un élément dans silverlight
'------------------------------------------------------------------------------
' pxaml : code XAML : ex. : "<TextBlock>J\'ajoute un texte</TextBlock>"
' pDocument : un document HTML
' pObjet : l'Id de l'objet Silverlight dans le document HTML
' pElement : le nom de l'élément parent
' pPosition : position optionnelle de l'élément
'------------------------------------------------------------------------------
Public
Function
SLInsertElement
(
ByVal
pxaml As
String
, pDocument As
Object, pObject As
String
, _
pElement As
String
, Optional
pPosition As
Long
=
-
1
)
Dim
sScript As
String
sScript =
"var plugin = document.getElementById('"
&
pObject &
"');"
&
vbCrLf
&
_
"var element = plugin.content.CreateFromXaml('"
&
pxaml &
"');"
&
vbCrLf
If
pPosition =
-
1
Then
sScript =
sScript &
"plugin.content.FindName('"
&
pElement &
"').children.add (element);"
Else
sScript =
sScript &
"plugin.content.FindName('"
&
pElement &
"').children.insert (element,"
&
pPosition &
");"
End
If
pDocument.parentWindow.execscript
sScript
End
Function
Cette fonction génère le code JavaScript nécessaire et l'exécute.
La fonction AddElement n'est plus utile dans le JavaScript du fichier silver1.html.
On pourra alors écrire :
SLInsertElement "<TextBlock>J\'ajoute un texte</TextBlock>"
, pDisp.Document
, "SilverLight1"
, "secondcanvas"
SLInsertElement "<TextBlock Canvas.Top=""15"">Et un deuxième</TextBlock>"
, pDisp.Document
, "SilverLight1"
, "secondcanvas"
On a ici ajouté deux textes.
Par défaut les éléments sont positionnés à l'origine du parent, en haut à gauche.
Pour les positionner, il faut utiliser les attributs Canvas.Top et Canvas.Left.
Bien ajouter Canvas, Top tout seul ne fonctionne pas.
Par contre, pour la taille, c'est Width et Height (sans le préfixe Canvas).
VII-H. Gérer les événements de la page SilverLight à partir de VBA▲
VII-H-1. Saisie de texte▲
Commençons par ajouter à notre fichier xaml deux zones de saisie de texte :
<Canvas
Name
=
"rootcanvas"
Background
=
"#50FFFF00"
xmlns
=
"http://schemas.microsoft.com/client/2007"
>
<!-- La Grille -->
<Grid
Name
=
"rootgrid"
ShowGridLines
=
"False"
>
<!-- Définition des colonnes -->
<Grid.ColumnDefinitions>
<ColumnDefinition
Width
=
"*"
/>
</Grid.ColumnDefinitions>
<!-- Définition des lignes -->
<Grid.RowDefinitions>
<RowDefinition
Height
=
"Auto"
/>
<RowDefinition
Height
=
"*"
/>
</Grid.RowDefinitions>
<!-- Texte d'en-tête dans la première ligne -->
<TextBlock
Name
=
"titre"
Grid.
Row
=
"0"
Grid.
Column
=
"0"
TextAlignment
=
"Center"
>
Premier écran<LineBreak/>
Silverlight
</TextBlock>
<!-- Canevas dans la deuxième ligne -->
<Border
BorderThickness
=
"2"
BorderBrush
=
"Blue"
Grid.
Row
=
"1"
Grid.
Column
=
"0"
>
<Canvas
Name
=
"secondcanvas"
Background
=
"#FFDDDD"
>
<TextBlock>
Utilisateur :</TextBlock>
<TextBox Canvas.
Left
=
"120"
Name
=
"Login"
/>
<TextBlock Canvas.
Top
=
"40"
>
Mot de passe :</TextBlock>
<PasswordBox Canvas.
Left
=
"120"
Canvas.
Top
=
"40"
Name
=
"Password"
/>
</Canvas>
</Border>
</Grid>
</Canvas>
Le contrôle TextBox permet de saisir du texte.
Le contrôle PasswordBox permet de saisir du texte masqué (pour un mot de passe donc).
Par défaut les contrôles de saisie font (à peu près) 1 caractère de large et s'étendent durant la saisie.
Pour éviter ceci ,il suffit d'ajouter un attribut de taille (Width) aux éléments :
<TextBlock>
Utilisateur :</TextBlock>
<TextBox
Width
=
"200"
Canvas.
Left
=
"120"
Name
=
"Login"
/>
<TextBlock Canvas.
Top
=
"40"
>
Mot de passe :</TextBlock>
<PasswordBox
Width
=
"200"
Canvas.
Left
=
"120"
Canvas.
Top
=
"40"
Name
=
"Password"
/>
Maintenant nous allons réagir à la saisie.
Pour capturer un événement d'un élément Silverlight, il faut créer un gestionnaire d'événements.
Nous avons déjà créé des gestionnaires d'événements aux chapitres IV-E et V-D-2.
C'est pour Silverlight la même procédure, il faut un objet ayant une méthode par défaut.
Créez un module de classe :
Option
Explicit
Public
Event SLEvent
(
sender As
Variant
, args As
Variant
)
Public
Sub
EventFromSL
(
sender As
Variant
, args As
Variant
)
'Attribute EventFromSL.VB_UserMemId = 0
RaiseEvent SLEvent
(
sender, args)
End
Sub
Sauvegardez-le sous le nom clEventsSL.
Puis exportez ce module, supprimez-le et décommentez la ligne 'Attribute ... du fichier exporté avant de le réimporter.
EventFromSL est alors la méthode par défaut de cette classe.
Pour une utilisation dans une application Internet Explorer, il faut que ce module soit public.
Définissez la propriété Instancing du module à 2 - PublicNotCreatable.
Le module peut rester privé si la page est affichée dans un contrôle WebBrowser.
Pour utiliser cet objet, il faut d'abord le déclarer en en-tête de module avec WithEvents :
Private
WithEvents oEventsTextChanged As
clEventsSL
Puis instanciez l'objet à l'ouverture du formulaire par exemple :
Set
oEventsTextChanged =
New
clEventsSL
Ce qui donne pour le code d'un userForm dans Excel :
Option
Explicit
Private
oSL As
Object
Private
WithEvents oEventsTextChanged As
clEventsSL
Private
Sub
UserForm_Initialize
(
)
Set
oEventsTextChanged =
New
clEventsSL
Me.ctlNav.Navigate
ThisWorkbook.Path
&
"/silver1.html"
End
Sub
Private
Sub
ctlNav_DocumentComplete
(
ByVal
pDisp As
Object, URL As
Variant
)
Set
oSL =
pDisp.Document.getElementById
(
"silverlight1"
).Object
While
Not
oSL.IsLoaded
DoEvents ' indispensable pour ne pas tout bloquer
Wend
End
Sub
Maintenant il faut affecter ce gestionnaire d'événements aux éléments, sur le ou les événements désirés.
Cela se fait avec la méthode AddEventListener :
' TextBox : http://msdn.microsoft.com/en-us/library/cc917833(v=VS.95).aspx
oSL.content.findname
(
"Login"
).addeventlistener
"TextChanged"
, oEvents
' PasswordBox : http://msdn.microsoft.com/en-us/library/cc917814(v=VS.95).aspx
oSL.content.findname
(
"Password"
).addeventlistener
"PasswordChanged"
, oEvents
En commentaire dans le code, il y a les liens vers les pages MSDN où trouver les noms d'événements.
On a choisi, pour tester, les événements de changement de texte.
Créez enfin la procédure événementielle en choisissant dans les listes déroulantes en haut du module de code : oEventsTextChanged et SLEvent :
Private
Sub
oEventsTextChanged_SLEvent
(
sender As
Variant
, args As
Variant
)
Stop
End
Sub
C'est cette procédure qui sera exécutée sur changement de texte dans un des contrôles.
On utilise le même objet pour les événements des deux contrôles, il faudra retrouver le contrôle initiateur de l'événement.
Comme il y a un point d'arrêt dans la procédure, si on modifie un texte l'exécution s'arrête.
On va en profiter pour étudier les paramètres sender et args.
sender est l'élément initiateur de l'événement.
sender.getvalue("name") nous permet de retrouver son nom.
Si on survole args on voit :
- TextChangedEventArgs pour l'utilisateur ;
- RoutedEventArgs pour le mot de passe.
Le type d'argument est donc fonction de l'événement.
Pour l'événement TextChanged du Login.
TextChangedEventArgs est défini ici : Membres TextChangedEventArgs.
Pour l'événement PasswordChange du Password :
RoutedEventArgs est défini ici : Membres RoutedEventArgs.
Je n'ai malheureusement pas réussi à extraire d'informations intéressantes de cet argument.
J'aurais aimé retrouver le nom de l'événement déclencheur (TextChanged ou PasswordChange).
Il faudra alors utiliser plusieurs objets de type clEventsSL pour gérer différents types d'événements.
Pour notre cas on va laisser tout dans la même procédure et vérifier le nom de l'objet sender.
Le texte est également lisible par VBA, en utilisant GetValue sur le sender pour lire ses propriétés.
Private
Sub
oEventsTextChanged_SLEvent
(
sender As
Variant
, args As
Variant
)
Select
Case
sender.getvalue
(
"name"
)
Case
"Login"
Debug.Print
"Modification de Login :"
&
sender.getvalue
(
"text"
)
Case
"Password"
Debug.Print
"Modification de Password :"
&
sender.getvalue
(
"password"
)
End
Select
End
Sub
VII-H-2. Gestion de la souris▲
Comme pour les événements de texte auparavant, il faut d'abord déclarer un objet en en-tête de module avec WithEvents :
Private
WithEvents oEventsMouseDown As
clEventsSL
Puis instancier cet objet à l'ouverture du formulaire par exemple :
Set
oEventsMouseDown =
New
clEventsSL
Créez enfin la procédure événementielle en choisissant dans les listes déroulantes en haut du module de code : oEventsMouseDown et SLEvent :
Private
Sub
oEventsMouseDown_SLEvent
(
sender As
Variant
, args As
Variant
)
stop
End
Sub
Pour déclencher l'événement il faut affecter l'objet à l'événement de l'élément voulu.
On va capturer les événements de click avec le bouton gauche de la souris sur le canevas racine.
oSL.content.findname
(
"rootcanvas"
).addeventlistener
"MouseLeftButtonDown"
, oEventsMouseDown
Ce code est à placer après la boucle d'attente de chargement du plugin.
Si on clique sur la page (sauf si on clique sur une zone de saisie), l'événement est déclenché.
Le code s'arrête sur l'instruction Stop, le temps de faire quelques investigations.
Survolez sender => il s'affiche son type : Canvas.
Pour voir son nom :
MsgBox
sender.getvalue
(
"name"
)
Quel que soit l'élément sur lequel vous cliquez, on affiche "rootcanvas" qui est le nom de l'élément auquel on a affecté le gestionnaire d'événement.
L'événement est donc transmis de l'élément sur lequel on clique à l'élément qui le contient.
Si vous survolez args (ou que vous affichez la valeur de args.toString), vous voyez : MouseButtonEventArgs.
Cet argument contient des informations intéressantes et exploitables :
- Source est l'élément déclencheur de l'événement (potentiellement différent de sender).
- GetPosition nous permet de trouver la position du clic (absolue ou relative).
MsgBox
"Gérer par "
&
sender.tostring
&
" : "
&
sender.getvalue
(
"name"
) &
vbCrLf
&
_
"Envoyé par "
&
args.getvalue
(
"Source"
).tostring
&
" : "
&
args.getvalue
(
"Source"
).getvalue
(
"name"
) &
vbCrLf
&
_
"Position absolue "
&
args.GetPosition
(
Null
).getvalue
(
"x"
) &
":"
&
args.GetPosition
(
Null
).getvalue
(
"y"
) &
vbCrLf
&
_
"Position relative "
&
args.GetPosition
(
args.getvalue
(
"Source"
)).getvalue
(
"x"
) &
":"
&
_
args.GetPosition
(
args.getvalue
(
"Source"
)).getvalue
(
"y"
)
Ce code nous affiche par exemple :
Gérer par Canvas : rootcanvas
Envoyé par Canvas : secondcanvas
Position absolue 380:229
Position relative 378:182
En remarque bien que sender est toujours le canevas racine, et que la valeur de "Source" est l'élément sur lequel on a cliqué.
Pour trouver la position, il faut préciser Null pour avoir la position absolue (c'est-à-dire l'origine en haut à gauche de la page).
Pour avoir la position à l'intérieur d'un élément, il faut préciser cet élément dans l'appel à GetPosition.
GetPosition renvoie une structure de type Point qui possède des propriétés X et Y.
Lien MSDN pour la gestion de la souris : Silverlight Mouse Support
Les fichiers xaml, HTML et un fichier Excel de test de ce chapitre sont disponibles sur ce lien.
VII-I. Dessiner avec la souris▲
Pour dessiner des traits, on peut utiliser l'objet InkPresenter.
Un trait est ajouté à la collection Strokes et possède des attributs de taille et couleur.
Voici un exemple à télécharger pour Excel : Tutoriel souris(miroir HTTP)
Lien MSDN pour l'objet InkPresenter : InkPresenter
Les fichiers xaml, HTML et un fichier Excel de test de ce chapitre sont disponibles sur ce lien.
Si vous n'avez pas Excel, voici l'extrait des codes :
<HTML>
<script type="text/javascript">
function OnErrorEventHandler(sender, errorArgs)
{
// Create the error message to display.
var errorMsg = "Silverlight Error: \n\n";
// Specify error information common to all errors.
errorMsg += "Error Type: " + errorArgs.errorType + "\n";
errorMsg += "Error Message: " + errorArgs.errorMessage + "\n";
errorMsg += "Error Code: " + errorArgs.errorCode + "\n";
// Determine the type of error and add specific error information.
switch(errorArgs.errorType)
{
case "RuntimeError":
// Display properties specific to RuntimeErrorEventArgs.
if (errorArgs.lineNumber != 0)
{
errorMsg += "Line: " + errorArgs.lineNumber + "\n";
errorMsg += "Position: " + errorArgs.charPosition + "\n";
}
errorMsg += "MethodName: " + errorArgs.methodName + "\n";
break;
case "ParserError":
// Display properties specific to ParserErrorEventArgs.
errorMsg += "Xaml File: " + errorArgs.xamlFile + "\n";
errorMsg += "Xml Element: " + errorArgs.xmlElement + "\n";
errorMsg += "Xml Attribute: " + errorArgs.xmlAttribute + "\n";
errorMsg += "Line: " + errorArgs.lineNumber + "\n";
errorMsg += "Position: " + errorArgs.charPosition + "\n";
break;
default:
break;
}
// Display the error message.
alert(errorMsg);
}
function OnResizeEventHandler(sender, args)
{
sender.width = sender.gethost().content.actualwidth;
sender.height = sender.gethost().content.actualheight;
sender.findname("rootgrid").width = sender.gethost().content.actualwidth;
sender.findname("rootgrid").height = sender.gethost().content.actualheight;
}
</script>
<body topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0">
<object id="SilverLight1" data="data:application/x-silverlight," type="application/x-silverlight-2"
width="100%" height="100%">
<param name="source" value="silvermouse.xaml"/>
<param name="onerror" value="OnErrorEventHandler" />
<param name="onresize" value="OnResizeEventHandler" />
<!-- Display installation image. -->
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50303.0"
style="text-decoration: none;">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376"
alt="Get Microsoft Silverlight"
style="border-style: none"/>
</a>
</object>
</body>
</HTML>
<Canvas
Name
=
"rootcanvas"
Background
=
"#50FFFF00"
xmlns
=
"http://schemas.microsoft.com/client/2007"
>
<!-- La Grille -->
<Grid
Name
=
"rootgrid"
ShowGridLines
=
"False"
>
<!-- Définition des colonnes -->
<Grid.ColumnDefinitions>
<ColumnDefinition
Width
=
"*"
/>
</Grid.ColumnDefinitions>
<!-- Définition des lignes -->
<Grid.RowDefinitions>
<RowDefinition
Height
=
"Auto"
/>
<RowDefinition
Height
=
"*"
/>
</Grid.RowDefinitions>
<!-- Texte d'en-tête dans la première ligne -->
<TextBlock
Name
=
"titre"
Grid.
Row
=
"0"
Grid.
Column
=
"0"
TextAlignment
=
"Center"
>
Dessinez en cliquant sur le bouton gauche de la souris.
</TextBlock>
<!-- Canevas dans la deuxième ligne -->
<!-- <Border BorderThickness="2" BorderBrush="Blue" Grid.Row="1" Grid.Column="0">-->
<InkPresenter Grid.
Row
=
"1"
Grid.
Column
=
"0"
Background
=
"#500000FF"
Name
=
"inkPresenterElement"
/>
<!--</Border>-->
</Grid>
</Canvas>
Option
Explicit
Private
oSL As
Object
Private
WithEvents oInkPresenterMouseDown As
clEventsSL
Private
WithEvents oInkPresenterMouseMove As
clEventsSL
Private
WithEvents oInkPresenterMouseUp As
clEventsSL
Private
newStroke As
Integer
' indice du trait en cours de dessin (doit être un entier Integer)
Private
Const
daWidth As
Integer
=
2
Private
Const
daHeight As
Integer
=
2
Private
Const
daColor As
String
=
"Blue"
Private
Const
daOutlineColor As
String
=
"Black"
Private
Sub
oInkPresenterMouseDown_SLEvent
(
sender As
Variant
, args As
Variant
)
sender.CaptureMouse
' Ajout du trait
SLAddStroke "<Stroke><Stroke.DrawingAttributes/></Stroke>"
, Me.ctlNav.Document
, _
"SilverLight1"
, "inkPresenterElement"
' Indice = nombre de traits - 1
newStroke =
sender.getvalue
(
"strokes"
).getvalue
(
"Count"
) -
1
' attributs
With
sender.getvalue
(
"strokes"
).getitem
(
CInt
(
newStroke)).getvalue
(
"DrawingAttributes"
)
.Width
=
daWidth
.Height
=
daHeight
.Color
=
daColor
.OutlineColor
=
daOutlineColor
End
With
' ajoute les points
sender.getvalue
(
"strokes"
).getitem
(
CInt
(
newStroke)).getvalue
(
"StylusPoints"
).AddStylusPoints
_
args.GetStylusPoints
(
args.getvalue
(
"Source"
))
End
Sub
Private
Sub
oInkPresenterMouseMove_SLEvent
(
sender As
Variant
, args As
Variant
)
On
Error
GoTo
gestion_erreurs
If
newStroke <>
-
1
Then
sender.getvalue
(
"strokes"
).getitem
(
CInt
(
newStroke)).getvalue
(
"StylusPoints"
).AddStylusPoints
_
args.GetStylusPoints
(
args.getvalue
(
"Source"
))
End
If
Exit
Sub
gestion_erreurs
:
' Erreur si dépasse le inkpresenter
End
Sub
Private
Sub
oInkPresenterMouseUp_SLEvent
(
sender As
Variant
, args As
Variant
)
newStroke =
-
1
sender.ReleaseMouseCapture
End
Sub
Private
Sub
UserForm_Initialize
(
)
newStroke =
-
1
Set
oInkPresenterMouseDown =
New
clEventsSL
Set
oInkPresenterMouseMove =
New
clEventsSL
Set
oInkPresenterMouseUp =
New
clEventsSL
Me.ctlNav.Navigate
ThisWorkbook.Path
&
"/silvermouse.html"
End
Sub
Private
Sub
ctlNav_DocumentComplete
(
ByVal
pDisp As
Object, URL As
Variant
)
Set
oSL =
pDisp.Document.getElementById
(
"silverlight1"
).Object
While
Not
oSL.IsLoaded
DoEvents ' indispensable pour ne pas tout bloquer
Wend
oSL.content.findname
(
"inkPresenterElement"
).addeventlistener
"MouseLeftButtonDown"
, oInkPresenterMouseDown
oSL.content.findname
(
"inkPresenterElement"
).addeventlistener
"MouseMove"
, oInkPresenterMouseMove
oSL.content.findname
(
"inkPresenterElement"
).addeventlistener
"MouseLeftButtonUp"
, oInkPresenterMouseUp
End
Sub
'------------------------------------------------------------------------------
' Insère un trait dans un InkPresenter dans silverlight
'------------------------------------------------------------------------------
' pxaml : code XAML
' pDocument : un document HTML
' pObjet : l'Id de l'objet Silverlight dans le document HTML
' pElement : le nom de l'élément parent
' pPosition : position optionnelle de l'élément
'------------------------------------------------------------------------------
Public
Function
SLAddStroke
(
ByVal
pxaml As
String
, pDocument As
Object, pObject As
String
, pElement As
String
)
Dim
sScript As
String
sScript =
"var plugin = document.getElementById('"
&
pObject &
"');"
&
vbCrLf
&
_
"var element = plugin.content.CreateFromXaml('"
&
pxaml &
"');"
&
vbCrLf
sScript =
sScript &
"plugin.content.FindName('"
&
pElement &
"').strokes.add (element);"
pDocument.parentWindow.execscript
sScript
End
Function
L'exemple ci-dessus utilise le module de classe clEventsSL vu précédemment.
Voici une image obtenue avec cet exemple :
VII-J. Capture d'écran▲
Il n'existe pas de méthode standard (sauf dans le code XAML managé compilé).
On peut juste envisager une capture d'écran via l'API Windows.
Je n'ai pas à ce jour de code à vous proposer...
VII-K. Images et Vidéos▲
Le plugin Silverlight accepte un nombre limité de formats de vidéos et d'images.
VII-K-1. Images▲
Silverlight ne connaît que les formats d'image PNG et JPG.
Exemple d'intégration d'une image :
<Image
Name
=
"MyImage"
Source
=
"logoofficeweb.jpg"
Width
=
"150"
/>
Les images peuvent aussi être utilisées pour remplir une forme :
<Ellipse
Width
=
"200"
Height
=
"100"
Stroke
=
"Black"
StrokeThickness
=
"1"
>
<Ellipse.Fill>
<ImageBrush
ImageSource
=
"logoofficeweb.jpg"
/>
</Ellipse.Fill>
</Ellipse>
VII-K-2. Vidéos▲
Vous trouverez sur MSDN la liste des formats de vidéo supportés : Supported Media Formats, Protocols, and Log Fields.
Pour insérer une vidéo, utilisez l'élément MediaElement :
<MediaElement
Name
=
"MyVideo"
Source
=
"myvideo.wmv"
Width
=
"150"
Height
=
"150"
/>
Les vidéos peuvent aussi être utilisées pour remplir une forme :
<MediaElement
Name
=
"MyVideo"
Source
=
"myvideo.wmv"
Opacity
=
"0.0"
IsMuted
=
"True"
/>
<Ellipse
Width
=
"150"
Height
=
"150"
>
<Ellipse.Fill>
<VideoBrush
SourceName
=
"MyVideo"
/>
</Ellipse.Fill>
</Ellipse>
Il faut d'abord créer un MediaElement nommé et le rendre invisible (Opacity) et en sourdine (IsMuted).
Réutilisez ensuite le nom de cet élément dans l'élément VideoBrush.
Pour plus d'information sur l'élément VideoBrush :VideoBrush Overview.
VII-L. Transformations▲
Utilisez l'élément RenderTransform pour appliquer des transformations à un élément :
Exemple d'une image dont les transformations sont centrées sur l'origine (avec RenderTransformOrigin).
L'image est tournée de 30 ° et réduite en taille de moitié.
<Canvas
xmlns
=
"http://schemas.microsoft.com/client/2007"
>
<Image
Name
=
"MyImage"
Source
=
"logoofficeweb.jpg"
Width
=
"350"
RenderTransformOrigin
=
"0.5,0.5"
>
<Image.RenderTransform>
<TransformGroup>
<RotateTransform
Name
=
"MyRotate"
Angle
=
"30"
/>
<ScaleTransform
Name
=
"MyScale"
ScaleX
=
"0.5"
ScaleY
=
"0.5"
/>
</TransformGroup>
</Image.RenderTransform>
</Image>
</Canvas>
VII-M. Animations▲
Des animations peuvent être obtenues avec un élément Storyboard.
Sur le lien ci-dessus, vous avez un exemple d'animation d'opacité.
Voici le code XAML pour animer le même rectangle de gauche à droite :
<Canvas
xmlns
=
"http://schemas.microsoft.com/client/2007"
>
<Rectangle
Name
=
"MyAnimatedRectangle"
Width
=
"100"
Height
=
"100"
Fill
=
"Blue"
>
<Rectangle.Triggers>
<EventTrigger
RoutedEvent
=
"Rectangle.Loaded"
>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.
TargetName
=
"MyAnimatedRectangle"
Storyboard.
TargetProperty
=
"(Canvas.Left)"
From
=
"0"
To
=
"400"
Duration
=
"0:0:2"
AutoReverse
=
"True"
RepeatBehavior
=
"Forever"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
</Canvas>
Le tutoriel suivant, bien qu'écrit pour C#, contient des informations intéressantes pour les animations en XAML : Les animations avec Silverlight.
VII-N. Intégrer le code XAML dans la page HTML : Online XAML▲
Au lieu d'utiliser un fichier externe, il est possible d'intégrer le code XAML à la page HTML.
Voici un article de MSDN qui explique cette possibilité : Utilisation du XAML inline.
VII-O. Peut-on utiliser des barres de défilement ?▲
Non, l'objet ScrollView n'est disponible que pour une application compilée (API managée).
On peut agrandir le plugin (par exemple une taille à 200 %) et avoir alors des barres de défilement HTML sur tout le plugin, mais pas sur un élément particulier.
VII-P. Conclusion Silverlight▲
Si le code XAML non compilé est très restreint par rapport à ce que Silverlight peut offrir, on arrive tout de même à faire de beaux écrans.
L'intérêt de Silverlight dans Office reste à démontrer ; un écran d'accueil (SplashScreen) pourrait être du plus bel effet ;o).