A while back I blogged about a technique for allowing two Silverlight control instances to communicate. It involved having one of the controls call out from C# into a simple JavaScript bridge, and then having the bridge call into the other control by calling from JavaScript into C#. It was a practical use for the Silverlight DOM integration features that let you call from C# to JavaScript and JavaScript to C#, and it was, I thought, a pretty cool sample.
I was talking to a developer friend a couple of weeks later and he said “Why do you even need the JavaScript bridge? Why not use ScriptObject to call directly from one control instance to the other?” Great question. In fact, the four or five lines of JavaScript code in the sample I published were completely unnecessary, and I’ll be showing a revised—and much cooler—version of the sample app at the PDC. Here’s how it works.
The original sample featured two Silverlight controls: the source control and the target control. When you moved a ball in the source control, the target control mirrored your moves with a ball of its own. The calling sequence looked like this:
// Source control
HtmlPage.Window.Invoke(“moveBall”, x, y);
// JavaScript bridge
var _target = null;
function moveBall(x, y)
{
if (_target == null)
_target = document.getElementById(‘TargetControl’);
_target.content.other.MoveBall(x, y);
}
// Target control
[ScriptableMember]
public void MoveBall(double x, double y)
{
Ball.SetValue(Canvas.LeftProperty, x);
Ball.SetValue(Canvas.TopProperty, y);
}
First the source control called the JavaScript moveBall function, and then moveBall called the C# MoveBall method in the second control. Not shown is the call to HtmlPage.RegisterScriptableObject that registered the target control with the script name “other.”
In the revised code sample, the source control does this:
private ScriptObject _other = null;
// Returns a ScriptObject reference to the target control
private ScriptObject OtherControl
{
get
{
if (_other == null)
{
HtmlElement targetControl =
HtmlPage.Document.GetElementById(“TargetControl”);
ScriptObject targetContent =
(ScriptObject)targetControl.GetProperty(“content”);
_other = (ScriptObject)targetContent.GetProperty(“other”);
}
return _other;
}
}
// Call the target control’s Move Ball method
OtherControl.Invoke(“MoveBall”, x, y);
The target control’s MoveBall method is now called directly, thanks to the ScriptObject reference returned by the OtherControl property and the magic of ScriptObject.Invoke. This is much cleaner, and it doesn’t require a single line of JavaScript.
But enough about the HTML bridge. Tomorrow’s cool Silverlight trick will involve a different subject entirely.