mardi 22 avril 2008

Création d'un menu menu dynamique en Silverlight 1.0

Sur ce tutorial nous allons voir comment créer dynamiquement un menu en Sivlerlight 1.0 avec JavaScript.
Nous aborderons des notions tel que le chargement de XAML à la volée, par la méthode createFromXAML, le chargement de fichier XML par l' objet Downloader et le parcours de l'arbre en XPATH grave à une classe nommé XDoc.

Pour commencer, nous allons ouvrir Blend 2.5 (March 2008 preview), nous allons créer un projet "Silverlight 1 Site :

Une fois le projet créé nous allons ajouter une nouvelle page XAML, menuItem.xaml qui contiendra le bloc du menu qui sera  a dupliquer :

 

Dans ce fichier nous allons ajouter un fond qui sera un rectangle auquel on appliquera un dégradé du rouge vers le blanc, ensuite nous ajouterons un TextBlock qui contiendra le libellé de notre  Item :

<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Scene">
<Rectangle Width="100" Height="40" Stroke="#FF000000" x:Name="rFond_i_">
<Rectangle.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Name="gsColorEnd_i_" Color="#FFFF0000" Offset="0"/>
<GradientStop Color="#FFFFFFFF" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock Width="100" Height="28" Canvas.Top="8" Text="TextBlock" TextWrapping="Wrap" x:Name="tbLibelle_i_"/>
</Canvas>


Comme ce XAML a pour but d' être injecter plusieurs fois dans la page nous suffixerons tous les nom d' occurrence par le suffixe "_i_" que nous remplacerons plus tard lors de l' injection de ce XAML dans notre scène principale.

Nous nommons donc notre rectangle "rFond_i_", notre TexBlock "tbLibelle_i_" et enfin la propriété de la couleur de départ du dégradé "gsColorEnd_i_".



Nous allons maintenant créer un fichier "data.xml" qui contiendra la définition des différents élément de notre menu :



<menu>
<item>
<libelle>ITEM 1</libelle>
<couleur>#FFFF0000</couleur>
</item>
<item>
<libelle>ITEM 2</libelle>
<couleur>#FF00FF00</couleur>
</item>
<item>
<libelle>ITEM 2</libelle>
<couleur>#FF0000FF</couleur>
</item>
</menu>


Nous l' ajoutons maintenant à notre solution :



Maintenant nous allons déclarer un prototype et une fonction qui vont nous être nécessaire pour plus tard, la première est la fonction noRetourChariot, qui va nous permettre d' enlever tous les retours chariots lors de de la récupération de notre fichier XML :



function noRetourChariot(str){
str = str.replaceAll("\r","");
str = str.replaceAll("\n","");
return str;
}




La secondes est un prototype de String permettant d' effectuer un Replace récursif dans une chaîne de caractères :



String.prototype.replaceAll = function( strTarget, strSubString ){
var strText = this;
var intIndexOfMatch = strText.indexOf( strTarget );
while (intIndexOfMatch != -1){
strText = strText.replace( strTarget, strSubString );
intIndexOfMatch = strText.indexOf( strTarget );
}
return( strText );
}


Passons maintenant au code, nous allons charger le fichier XML grace à l'objet Downloader à l'initialisation de notre composant :



SilverlightSite1.Page.prototype =
{
handleLoad: function(control, userContext, rootElement)
{
this.control = control; this.rootElement= rootElement;



// Retrieve a reference to the plug-in.
var slPlugin = sender.getHost();

// Create a Downloader object.
var downloader = slPlugin.createObject("downloader");

// Add DownloadProgressChanged and Completed events.
downloader.addEventListener("completed", Silverlight.createDelegate(this, this.onCompleted));
downloader.open("GET", "data.xml");

// Execute the Downloader request.
downloader.send();

},

// event handler onCompleted
onCompleted: function(sender, eventArgs)
{
this.dataXML = noRetourChariot(sender.ResponseText);
}
}


une fois le fichier data.xml chargé comme nous  nous sommes abonnés à l' événement "completed" de l' objet Donwloader la fonction onCompleted est appelé, nous stockons ensuite le contenu du fichier XML dans la variable this.data en y appliquant la fonction "noRetourChariot".



Maintenant nous allons chargé le contenu du fichier menuItem.xaml, nous procédons donc de la même façon en utilisant l' objet Downloader à nouveau :



 



	// event handler onCompleted
onCompleted: function(sender, eventArgs)
{
this.dataXML = noRetourChariot(sender.ResponseText);

var slPlugin = sender.getHost();
var downloader = slPlugin.createObject("downloader");
downloader.addEventListener("completed", Silverlight.createDelegate(this, this.onCompletedMenuItem));
downloader.open("GET", "menuItem.xaml");

// Execute the Downloader request.
downloader.send();
},
// event handler onCompletedMenuItem
onCompletedMenuItem: function(sender, eventArgs)
{
this.menuItemXAML = noRetourChariot(sender.ResponseText);
}


Le contenu de notre fichier XAML est maintenant stocké dans this.menuItemXAML nous allons maintenant parser contenu de la variable, et injecter dans la scène principale :



// event handler onCompletedMenuItem
onCompletedMenuItem: function(sender, eventArgs)
{
this.menuItemXAML = noRetourChariot(sender.ResponseText);
this.data = new XMLDoc(this.dataXml);
var item = this.data.selectNode("/item").getElements();
var lg = item.length;

var posX = 0;

for(var i=0;i<lg;i++)
{
var objElement = item[i];
var itemObject = this.control.content.createFromXaml(this.menuItemXAML.replaceAll("_i_", i));
itemObject.findName("gsColorEnd"+i).Color = objElement.selectNode("couleur").getText();
itemObject.findName("tbLibelle"+i).Color = objElement.selectNode("libelle").getText();
itemObject["Canvas.Left"] = posX;
this.rootElement.children.add(itemObject);
posX+=100;
}
}


Il suffit maintenant de retourner dans Blend de faire F5 pour publier le projet and it works!!!!!

lundi 21 avril 2008

Utilisation d'un Timer en Silverlight 2

L'utilisation d'un timer est souvent utile pour déclencher des actions aprés un temps donné. Dans cette exemple vous trouverez comment masquer des élements de votre vue aprés une inactivité de la souris de 2 secondes.

Nous allons créer un rectangle bleu portant le nom "rRectangle".

<UserControl x:Class="SilverlightApplication1.Page"
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<Rectangle x:Name="rRectangle" Width="100" Height="100" Fill="Blue" />
</Grid>
</UserControl>


Tout dabord dans l'initialisation de votre UserControl il faut s'abonner à l'évenement du mouvement de la souris :



namespace SilverlightApplication1
{
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
this.MouseMove += new MouseEventHandler(Page_MouseMove);
}

void Page_MouseMove(object sender, MouseEventArgs e)
{
throw new NotImplementedException();
}
}
}


A chaque fois que l'on bouge la souris la fonction Page_MouseMove est appelé. Il faut stocké le DateTime actuel.



public partial class Page : UserControl
{
private DateTime _lastMove = DateTime.Now;
public Page()
{
InitializeComponent();
this.MouseMove += new MouseEventHandler(Page_MouseMove);
}

void Page_MouseMove(object sender, MouseEventArgs e)
{
_lastMove = DateTime.Now;
}
}


Maintenant nous allons créer un Timer en utilisant la classe System.Windows.Threading.DispatcherTimer, en définissant un interval de 2 secondes.



public partial class Page : UserControl
{
private DateTime _lastMove = DateTime.Now;
public Page()
{
InitializeComponent();
this.MouseMove += new MouseEventHandler(Page_MouseMove);
System.Windows.Threading.DispatcherTimer dt = new System.Windows.Threading.DispatcherTimer();
dt.Interval = new TimeSpan(0, 0, 2);
dt.Tick += new EventHandler(dt_Tick);
dt.Start();
}

void dt_Tick(object sender, EventArgs e)
{
throw new NotImplementedException();
}

void Page_MouseMove(object sender, MouseEventArgs e)
{
_lastMove = DateTime.Now;
}
}


La fonction dt_Tick est donc appelée toutes les deux secondes.

Nous allons donc comparer le DateTime actuel avec le _lastMove stocké si la différence est supérieur a deux secondes on masque le rectangle et lorsque l'on bouge la souris on affiche le rectangle.



public partial class Page : UserControl
{
private DateTime _lastMove = DateTime.Now;
public Page()
{
InitializeComponent();
this.MouseMove += new MouseEventHandler(Page_MouseMove);
System.Windows.Threading.DispatcherTimer dt = new System.Windows.Threading.DispatcherTimer();
dt.Interval = new TimeSpan(0, 0, 2);
dt.Tick += new EventHandler(dt_Tick);
dt.Start();
}

void dt_Tick(object sender, EventArgs e)
{
DateTime diff = DateTime.Now - _lastMove;
if (diff.Second > 2)
{
rRectangle.Visibility = Visibility.Collapsed;
}
}

void Page_MouseMove(object sender, MouseEventArgs e)
{
_lastMove = DateTime.Now;
rRectangle.Visibility = Visibility.Visible;
}
}


Voila si l'on lance l'application et que la souris reste immobile pendant plus de deux sedondes le rectangle disparaitra et lorsque l'on éffectuera un mouvement avec la souris celui ci réapparaitra.