W poprzednim artykule poświeconym połączeniom pomiędzy Silverlight-em, a kodem HTML (link), pokazałem jak w prosty sposób wskazać elementy strony html z poziomu aplikacji Silverlight i je użyć. Dowiedzieliśmy się także, w jaki sposób podpiąć Silverlight-a pod zdarzenia z kodu html. Całość zaowocowała nam "grą" w Ping Ponga :)
W tym artykule, chciałem krótko pokazać w jaki sposób możemy wywołać metody aplikacji Silverlight-a z kodu javascript i na odwrót, czyli metody javascript z kodu aplikacji Silverlight. Funkcjonalność ta okazuje się bardzo przydatna, szczególnie przy pracy z Virtual Earthem, Google Maps, obiektami JSONowymi i innymi aplikacjami/skryptami stworzonymi w javascript-cie.
Agenda
- Odwołanie do metody w javascript-cie z Silverlight-a
- Odwołanie do kodu aplikacji Silverlight, z javascript-u
- Obsługa event-ów wywołanych w Silverlight-cie, w kodzie javascript
- Przykładowy działający kod
Odwołanie do metody w javascript-cie z Silverlight-a
W pliku cs (np. Page.cs) dodajemy import Browser-a:
using System.Windows.Browser;
a w pliku javascript (np. Test.js), utworzonym przez nas w projekcie, dodajemy metodę
function testMethod(nothing) {
window.alert("[javascript] hello from javascript!");
}
i wywołujemy ją z kodu Silverlight-a (Page.cs):
Object[] args = null;
Object result = HtmlPage.Window.Invoke("testMethod", args);
, parametr args jest opcjonalny, tak samo jak wartość zwracana - result.
Plik Test.js musi być podłączony do strony html/aspx, która zawiera aplikacje Silverlight
<script type="text/javascript" src="Test.js"></script>
Alternatywnie, metoda testMethod może znajdować się bezpośrednio w pliku html/aspx, za pośrednictwem znaczników
<script type="text/javascript"> ... </script>
Odwołanie do kodu aplikacji Silverlight, z javascript-u
W celu odwołania się do Silverlight-a, musimy oznaczyć nasze zmienne, klasy, properties-y i eventy specjalnymi znacznikami ([ScriptableType], [ScriptableMember]). Dlatego też, klasa do której będziemy mogli się odwołać z javascript-u, będzie miała ten atrybut
[ScriptableType]
public class ScriptableClass
{
}
, natomiast jej zmienne i metody muszą mieć znaczniki ScriptableMember, np.:
[ScriptableType]
public class ScriptableClass
{
[ScriptableMember]
public string ScriptableMethod(string value){…}
[ScriptableMember]
public string val
{
get { return _val; }
set { _val = value; }
}
}
Następnie klasa musi zostać zarejestrowana na stronie html, poprzez wywołanie (np. w pliku Page.cs):
ScriptableClass scriptableClass;
scriptableClass = new ScriptableClass();
HtmlPage.RegisterScriptableObject("ScriptableClass", scriptableClass);
Na końcu, aby odwołać się do obiektu scriptableClass i jego metod/zmiennych w kodzie javascript, piszemy (w pliku Test.js):
var control = document.getElementById("Xaml1");
result = control.Content.ScriptableClass.scriptableMethod("Hello from javascript");
, a więc odnajdujemy kontrolkę Silverlight-a po jej id na stronie html/aspx (tu ta wartość może się u Was różnić jeśli modyfikowaliście kod html/aspx, w moim wypadku jest to "Xaml1") i wskazujcie zarejestrowany obiekt (ScriptableClass) i wywołujecie na nim metody (np. scriptableMethod(..)).
<div style="height: 100%;">
<asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/SilverlightApplication1.xap"
MinimumVersion="2.0.31005.0" Width="100%" Height="100%" />
</div>
Mamy już wszystko co trzeba. Po wywołaniu metody scriptableMethod() z klasy ScriptableClass w kodzie javascript, wykona się metoda w kodzie Silverlight-a.
Obsługa event-ów wywołanych w Silverlight-cie w kodzie javascript
Aby event mógł być obsłużony, należy utworzyć EventHandler (np. public event EventHandler SilverHandler) w aplikacji (ScriptableClass.cs)
[ScriptableType]
public class ScriptableClass
{
[ScriptableMember]
public event EventHandler SilverEvent;
public virtual void OnEvent(ScriptableEventArgs e)
{
if (null != SilverEvent)
{
SilverEvent(this, e);
}
e.val.ToString(); //value from javascript
}
}
Dodaliśmy także metodę OnEvent do ScriptableClass, która wywoła event SilverEvent. Teraz potrzebujemy metody która wywoła OnEvent (Page.cs):
ScriptableClass scriptableClass;
…
private void Button_Click_1(object sender, RoutedEventArgs e)
{
ScriptableEventArgs sea = new ScriptableEventArgs();
sea.val = "Event Args from Silverlight";
scriptableClass.OnEvent(sea);
}
Jak widać, pojawiła się dodatkowo klasa ScriptableEventArgs. Klasa ta, to nadpisana własna klasa EventArgs-ów. Musimy ją nadpisać, ponieważ potrzebujemy EventArgs-ów które są także typu [ScriptableType] ( ScriptableEventArgs.cs.)
[ScriptableType]
public class ScriptableEventArgs : EventArgs
{
private string _val;
[ScriptableMember]
public string val
{
get { return _val; }
set { _val = value; }
}
}
A więc mamy event (SilverEvent), mamy klasę argumentów (ScriptableEventArgs) oraz metodę która wywoła event. To co potrzebujemy, to obsługi eventa po stronie javascript (Test.js)
function loadedd(cos) {
var control = document.getElementById("Xaml1");
control.Content.ScriptableClass.SilverEvent = eventfunction;
}
function eventfunction(sender, args) {
value = args.val;
window.alert("[javascript] " + value);
args.val = "javascript values"; //return string
}
I tak, metoda eventfunction zostanie wywołana w momencie wciśnięcia przycisku w aplikacji Silverlight (Button_Click_1), ponieważ została przypisana do eventa SilverEvent. Przypisanie robimy podobnie jak dla wywołania metod z obiektu ScriptableClass, tylko tym razem przypisujemy metodę pod event.
control.Content.ScriptableClass.SilverEvent = eventfunction;
Ponieważ przypisanie może zostać wykonane dopiero po inicjalizacji aplikacji Silverlight, dlatego też w/w przypisanie eventa zostało zamknięte w metodę, którą ja wywołuje dopiero z metody Page_Loaded
public Page()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Page_Loaded);
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
HtmlPage.Window.Invoke("loadedd");
}
W ten sposób mam pewność, że event SilverEvent zostanie prawidłowo przypisany.
Przykładowy działający kod
Dla celów tego artykułu, stworzyłem demo aplikacji, która zapewnia prostą komunikację pomiędzy Silverlightem i javascriptem. W aplikacji mamy trzy przyciski:
- "Call javascript" – wywoła metodę w kodzie javascript (Test.js) z aplikacji Silverlight
- "Call Silverlight" – wywoła metodę javascritp, która wywoła metodę w aplikacji Silverlight
- "Call javascript event" – zostanie wywołany event (SilverEvent) w obiekcie ScriptableClass. Event zostanie przekazany i obsłużony w kodzie javascript. Kod javascript zwróci rezultaty poprzez użycie wartości w klasie ScriptableEventArgs
Plik Page.xaml:
<UserControl x:Class="SilverlightApplication1.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<Canvas x:Name="LayoutRoot" Background="White">
<Button Content="Call javascript" Click="Button_Click" Canvas.Left="100" Canvas.Top="50" />
<Button Content="Call javascript event" Click="Button_Click_1" Canvas.Left="100" Canvas.Top="100" />
</Canvas>
</UserControl>
Plik SilverlightApplicationTestPage.aspx
<%@ Page Language="C#" AutoEventWireup="true" %><%@ Register
Assembly="System.Web.Silverlight" Namespace="System.Web.UI.SilverlightControls"
TagPrefix="asp" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" style="height: 100%;">
<head runat="server">
<title>SilverlightApplication1</title>
<script type="text/javascript" src="Test.js"></script>
</head>
<body style="height: 100%; margin: 0;">
<form name="CallButtons" action="" method="GET">
<input type="button" name="button" value="Call Silverlight" onclick="testScriptableClassMethod()">
</form>
<br />
<form id="form1" runat="server" style="height: 100%;">
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div style="height: 100%;">
<asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/SilverlightApplication1.xap"
MinimumVersion="2.0.31005.0" Width="100%" Height="100%" />
</div>
</form>
</body>
</html>
Plik Page.cs
public partial class Page : UserControl
{
ScriptableClass scriptableClass;
public Page()
{
InitializeComponent();
scriptableClass = new ScriptableClass("Hello from Silverlight");
HtmlPage.RegisterScriptableObject("ScriptableClass", scriptableClass);
this.Loaded += new RoutedEventHandler(Page_Loaded);
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
HtmlPage.Window.Invoke("loadedd");
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Object[] args = null;
Object result = HtmlPage.Window.Invoke("testMethod", args);
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
ScriptableEventArgs sea = new ScriptableEventArgs();
sea.val = "Event Args from Silverlight";
scriptableClass.OnEvent(sea);
}
}
Plik ScriptableClass.cs
[ScriptableType]
public class ScriptableClass
{
private string value;
[ScriptableMember]
public event EventHandler SilverEvent;
public ScriptableClass(string val)
{
value = val;
}
[ScriptableMember]
public string scriptableMethod(string val)
{
string temp = value;
value = val;
return temp;
}
public virtual void OnEvent(ScriptableEventArgs e)
{
if (null != SilverEvent)
{
SilverEvent(this, e);
}
e.val.ToString(); //value from javascript
}
}
Plik ScriptableEventArgs.cs
[ScriptableType]
public class ScriptableEventArgs : EventArgs
{
private string _val;
[ScriptableMember]
public string val
{
get { return _val; }
set { _val = value; }
}
}
Plik Test.js
function testMethod(nothing) {
window.alert("[javascript] hello from javascript!");
}
function testScriptableClassMethod() {
var control = document.getElementById("Xaml1");
result = control.Content.ScriptableClass.scriptableMethod("Hello from javascript");
window.alert("[javascript] " + result);
}
function eventfunction(sender, args) {
value = args.val;
window.alert("[javascript] " + value);
args.val = "javascript values";
}
function loadedd(cos) {
var control = document.getElementById("Xaml1");
control.Content.ScriptableClass.SilverEvent = eventfunction;
}Pełny kod dema znajdziecie tu -> link
Resources
- Forum Silverlight.net: http://silverlight.net/forums/p/11550/44851.aspx#44851
- JSON by Corey: http://simplesilverlight.wordpress.com/2008/03/12/consume-a-json-object-in-silverlight/
- "From Silverlight to Javascript and Back Again" in IronPython: http://www.voidspace.org.uk/ironpython/silverlight/scriptable.shtml
Pozdrawiam,
JAcek Ciereszko

Brak komentarzy:
Prześlij komentarz