Per JavaScript auf Silverlight zugreifen

Irgendwann kommt sie, die Anforderung nach dem Zugriff per JavaScript auf Typen/Methoden, die sich innerhalb einer Silverlight-Anwendung befinden. Dies ist recht einfach und ohne viel Aufwand zu ermöglichen:

Verwaltete Typen und Methoden bereit stellen

Sämtliche Typen und Methoden müssen mit Attributen gekennzeichnet werden, damit ein Zugriff per JavaScript möglich ist. Hierfür stehen zwei Attribute zur Verfügung:

  • ScriptableTypeAttribute
  • ScriptableMemberAttribute

Mit dem ScriptableTypeAttribute wird ein verwalteter Typ gekennzeichnet, dessen öffentliche Eigenschaften, Methoden und Ereignisse für JavaScript zur Verfügung stehen. Hier muss der Type jedoch durch HtmlPage.RegisterCreateableType registriert werden. Nachfolgend findet sich die Klasse Calculator, die mit besagtem Attribut versehen ist und somit vollständig via JavaScript verfügbar gemacht werden soll.

#f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
#f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
[ScriptableType]

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">#0000ff">public #0000ff">class Calculator

{

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">    #0000ff">public #0000ff">int Add(#0000ff">int value1, #0000ff">int value2)

    {

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">        #0000ff">return value1 + value2;

    }

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}

Damit der Typ nun tatsächlich verfügbar ist, muss dieser Typ noch registriert werden:

#f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
#f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
#0000ff">public #0000ff">partial #0000ff">class MainPage : UserControl

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{

    #0000ff">public MainPage()

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">    {

        InitializeComponent();

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">        HtmlPage.RegisterCreateableType("Calculator", #0000ff">typeof(Calculator));

    }

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}

Dabei beschreibt der erste Parameter den Typalias, über den dieser dann in weiterer Folge verwendet werden kann. Der zweite Parameter stellt die Typinformationen des zu registrierenden Typs bereit.

Das ScriptableMemberAttribute beschreibt, dass auf bestimmte Methoden, Eigenschaften oder Ereignisse per JavaScript zugegriffen werden kann. Eine so gekennzeichnete Methode stellt sich wie folgt dar:

#f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
#f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
[ScriptableMember]

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">#0000ff">public #0000ff">void CreateAlert(#0000ff">string #0000ff">value)

{

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">    MessageBox.Show(#0000ff">value + " [via CreateAlert]");

}

Auch diese muss nun wieder registriert werden:

#f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
#f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
#0000ff">public #0000ff">partial #0000ff">class MainPage : UserControl

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{

    #0000ff">public MainPage()

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">    {

        InitializeComponent();

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">        HtmlPage.RegisterScriptableObject("Alerting", #0000ff">this);

    }

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}

Analog zum obigen Beispiel wird auch hier ein Alias vergeben. D.h. der Zugriff kann via Alerting passieren. Mehr dazu weiter unten.

Dieses Attribut bietet zusätzlich noch zwei Eigenschaften an, die verwendet werden können, um die Veröffentlichung zu beeinflussen:

  • EnableCreateableTypes: Per Standard werden automatisch Hilfsmethoden für den Zugriff generiert. Wird diese Eigenschaft auf false gestellt, passiert dies nicht und die Scriptwrapper müssen selbst erstellt werden (siehe auch RegisterCreateableType etc.)
  • ScriptAlias: Beschreibt den Namen des Members, wie er für JavaScript verfügbar gemacht werden soll. Standardmäßig wird der im verwalteten Code vergebene Name herangezogen.

Hinweis: Zu beachten ist, dass Einstellungen über das ScriptableMemberAttribute das Verhalten des ScriptableTypeAttribute überschreibt.

Verwaltete Typen und Methoden verwenden

Die Verwendung ist nun auch nicht weiter schwierig. Gehen wir davon aus, dass eine Schaltfläche auf der Webseite existiert, der im onClick die JavaScript-Funktion OnClick aufruft, das Silverlight-Host-Objekt besitzt als Id den Wert sl:

#f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
#f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
#0000ff">function OnClick() 

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{    

    #0000ff">var slCtl = document.getElementById("sl");

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">    #0000ff">var calculator = slCtl.Content.services.createObject('Calculator');

    alert(calculator.Add(2,5));

#f4f4f4; margin: 0em; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}

Die erste Zeile bezieht nun das Hostobjekt. In der zweiten Zeile geschieht der Aufruf createObject, dem der Typalias übergeben wird. Der Rückgabewert stellt ein JavaScript-Objekt unseres registrierten Typen dar.

Hinweis: Für weitere Informationen und Einschränkungen möchte ich an dieser Stelle auf den Artikel Constructing Managed Types from JavaScript hinweisen.

Auf die via dem ScriptableMemberAttribute freigegebene Methode kann über den folgenden Aufruf zugegriffen werden:

#f4f4f4; margin: 20px 0px 10px; padding-left: 4px; width: 97.5%; padding-right: 4px; font-family: 'Courier New', courier, monospace; direction: ltr; max-height: 200px; font-size: 8pt; overflow: auto; border-top: silver 1px solid; cursor: text; border-right: silver 1px solid; padding-top: 4px" id="codeSnippetWrapper">
#f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet">
slCtl.Content.Alerting.CreateAlert('From JavaScript');

Alerting beschreibt hier den registrierten Alias und CreateAlert selbst stellt die freigegebene Methode dar. Als Parameter wird ein Text übergeben, der dann auch in der Messagebox angezeigt wird:

MessageBox via JavaScript/Silverlight

Die vorgestellten Möglichkeiten sind ab Silverlight 3 verfügbar.

Fazit

Diese Features können im täglichen Leben mit Silverlight vieles ermöglichen. Dennoch sollte darauf geachtet werden, dass nicht grundsätzlich alles freigegeben wird, sondern lediglich die Teile, die tatsächlich öffentlich verfügbar sein müssen. Mögliche Szenarien sind beispielsweise das per JavaScript gesteuerte Nachladen/Refresh der in Silverlight angezeigten Daten, Navigationsunterstützung, Screenshot-Generierung usw.

Veröffentlicht von Norbert Eder

Ich bin ein leidenschaftlicher Softwareentwickler. Mein Wissen und meine Gedanken teile ich nicht nur hier im Blog, sondern auch in Fachartikeln und Büchern.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Cookie-Einstellungen
Auf dieser Website werden Cookie verwendet. Diese werden für den Betrieb der Website benötigt oder helfen uns dabei, die Website zu verbessern.
Alle Cookies zulassen
Auswahl speichern
Individuelle Einstellungen
Individuelle Einstellungen
Dies ist eine Übersicht aller Cookies, die auf der Website verwendet werden. Sie haben die Möglichkeit, individuelle Cookie-Einstellungen vorzunehmen. Geben Sie einzelnen Cookies oder ganzen Gruppen Ihre Einwilligung. Essentielle Cookies lassen sich nicht deaktivieren.
Speichern
Abbrechen
Essenziell (1)
Essenzielle Cookies werden für die grundlegende Funktionalität der Website benötigt.
Cookies anzeigen