Il fatto di avere a che fare con un runtime che permette di eseguire CLR non significa che non serva mai ricorrere all'uso di Javascript. M'è capitato ormai svariate volte di dovermi agganciare ad un evento del DOM HTML  o di dover in qualche modo interagire con altri oggetti nella pagina. In Silverlight 2.0 è possibile fare ciò per mezzo dell'oggetto HtmlPage che espone un punto di accesso al contenuto della pagina. Con esso possiamo ad esempio collegarci ad eventi del dom (AttachEvent) o modificare elementi e attributi o ancora invocare metodi Javascript.

A me è capitato ad esempio di dover interagire con uno ScriptControl che normalmente viene registrato nella pagina dalla Ajax Library ed è accessibile mediante il metodo $find(). Per invocare il medesimo metodo da Silverlight occorre usare la seguente sintassi:

   1: ScriptObject map = 
   2:     (ScriptObject)HtmlPage.Window.Invoke("$find", "map");

Ci sono casi in cui non è disponibile uno shortcut definito come nel caso di $find. Ad esempio se dobbiamo usare il metodo Sys.UI.DomElement.getBounds() le cose si complicano notevolmente:

   1: ((ScriptObject)((ScriptObject)((ScriptObject)((ScriptObject)
   2:         HtmlPage.Window
   3:             .GetProperty("Sys"))
   4:             .GetProperty("UI"))
   5:             .GetProperty("DomElement"))
   6:             .Invoke("getBounds", HtmlPage.Document.Body));

In sostanza dobbiamo cercare ricorsivamente le proprietà e alla fine invocare il metodo. COn un po' di codice è possibile scrivere dei metodi che aiutino a semplificare questo lavoro:

   1: /// <summary>
   2: /// Invokes the ex.
   3: /// </summary>
   4: /// <param name="so">The so.</param>
   5: /// <param name="methodPath">The method path.</param>
   6: /// <param name="args">The args.</param>
   7: /// <returns></returns>
   8: public static object InvokeEx(this ScriptObject so, string methodPath, params object [] args)
   9: {
  10:     IEnumerable<string> parts = Parse(methodPath);
  11:  
  12:     foreach (string part in parts)
  13:     {
  14:         if (part != parts.Last())
  15:             so = (ScriptObject)so.GetProperty(part);
  16:         else
  17:             return so.Invoke(part, args);
  18:     }
  19:  
  20:     throw new ArgumentException("methodPath");
  21: }
  22:  
  23: /// <summary>
  24: /// Gets the property ex.
  25: /// </summary>
  26: /// <param name="so">The so.</param>
  27: /// <param name="propertyPath">The property path.</param>
  28: /// <returns></returns>
  29: public static ScriptObject GetPropertyEx(this ScriptObject so, string propertyPath)
  30: {
  31:     IEnumerable<string> parts = Parse(propertyPath);
  32:  
  33:     foreach (string part in parts)
  34:         so = (ScriptObject)so.GetProperty(part);
  35:  
  36:     return so;
  37: }
  38:  
  39: /// <summary>
  40: /// Parses the specified path.
  41: /// </summary>
  42: /// <param name="path">The path.</param>
  43: /// <returns></returns>
  44: private static IEnumerable<string> Parse(string path)
  45: {
  46:     Match match = Regex.Match(path, @"(?<part>[^\.]*)(\.(?<part>[^\.]*))*");
  47:  
  48:     if (match.Success)
  52:         return from Capture cp in match.Groups["part"].Captures
  53:                select cp.Value;
  55:  
  56:     throw new ApplicationException(string.Format("Unable to parse path '{0}'}", path));
  57: }

Si tratta di un paio di Extension Method che estendono la classe ScriptObject e consentono di specificare il metodo o la proprietà con la classica notazione puntata. Il metodo principale, Parse, fa uso di una regular expression per verificare la validità della stringa passata ed estrarre la varie porzioni. Ecco come usare il nuovo metodo:

   1: ScriptObject bounds = 
   2:     (ScriptObject)HtmlPage.Window.InvokeEx("Sys.UI.DomElement.getBounds", HtmlPage.Document.Body);
Technorati Tag: ,,

Aggiungi Commento