Reputation: 5702
I'm evaluating the JavaScript/Silverlight interop capabilities and have been able to create a Silverlight instance using JavaScript and call methods on it. However, I now need a way of passing a JavaScript callback function to Silverlight.
Simply passing a JavaScript function to a Silverlight method expecting an Action doesn't work although the error suggest that it's intended to. What am I missing? The exception details:
Microsoft JScript runtime error: System.ArgumentException: Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
at System.Windows.Hosting.ScriptingInterface.GetDelegateForScriptObject(Type eventHandlerType, ScriptObject obj)
at System.Windows.Browser.ScriptObject.ConvertTo(Type targetType, Boolean allowSerialization)
at System.Windows.Hosting.ScriptingInterface.GetScriptParamValueForType(ScriptParam scriptParam, Type desiredType)
at System.Windows.Hosting.ScriptingInterface.ConvertFromScriptParams(ParameterInfo[] parameters, ScriptParam[] args)
at System.Windows.Browser.ManagedObjectInfo.ScriptMethod.Invoke(ManagedObject obj, InvokeType invokeType, ScriptParam[] args)
at System.Windows.Browser.ManagedObjectInfo.Invoke(ManagedObject obj, InvokeType invokeType, String memberName, ScriptParam[] args)
at System.Windows.Hosting.ManagedHost.InvokeScriptableMember(IntPtr pHandle, Int32 nMemberID, Int32 nInvokeType, Int32 nArgCount, ScriptParam[] pArgs, ScriptParam& pResult, ExceptionInfo& pExcepInfo)
Upvotes: 3
Views: 3044
Reputation: 36
My Code:
<!-- language: JavaScript -->
function sendText() {
return "Hi from Javascript!";
}
<!-- language: C# -->
string obj = HtmlPage.Window.Invoke("sendText", null) as string;
txtReturnData.Text = obj;
<!-- language: VB.Net -->
Dim obj As String = TryCast(HtmlPage.Window.Invoke("sendText", Nothing), String)
txtReturnData.Text = obj
Upvotes: 0
Reputation: 189437
There is a simpler way to pass Javascript function to Silverlight. All values from javascript can be represented by the ScriptObject
type, this includes a function. Its for this reason that the ScriptObject
has a InvokeSelf
method.
You can create a property as simple as:-
[ScriptableMember]
public ScriptObject Callback { get; set; }
Now lets say in Javascript we have this function:-
function sayHello(name)
{
alert("Hello " + name);
}
We can assign this to the property (assume the RegisterScriptableObject("Page", this)
has been done) with this JS:-
document.getElementById("mySL").Content.Page.Callback = sayHello;
Now in Silverlight code we can invoke this Callback with:-
Callback.InvokeSelf("Freed");
Upvotes: 1
Reputation: 5702
Apparently, this does work if the using a delegate type of EventHandler (or EventHandler<>), but not for other delegate types.
Upvotes: 0
Reputation: 16752
Without seeing your code I cannot say what you are doing wrong but I can describe what has worked for me in the past.
On the Silverlight side you need to register a class as a scriptable object. Then create a method that is marked as a ScriptableMember and takes a string that will be your passed in JavaScript method. I also added a method called InvokeCallback which will invoke the passed in javascript callback.
[ScriptableType]
public partial class Page : UserControl
{
private string jsCallback;
public Page()
{
InitializeComponent();
HtmlPage.RegisterScriptableObject("silverlightInterop", this);
}
[ScriptableMember]
public void RegisterCallback(string callback)
{
jsCallback = callback;
}
public boid InvokeCallback(string arg)
{
if(!string.IsNullOrEmpty(jsCallback))
{
System.Windows.Browser.HtmlPage.Window.Invoke(jsCallback, arg);
}
}
}
On the JavaScript side you can call the RegisterCallback method that you defined in Silverlight by grabbing the silverlight object on the page and calling the method off of the name "silverlightInterop" which we registered as the name of our scriptable object.
function jsCallback(someArg) {
alert(someArg);
}
var silverLightControl = document.getElementById("silverlightControl");
silverLightControl.content.silverlightInterop.RegisterCallback("jsCallback");
I hope this helps. I also have some sample code the demonstrates this which I wrote a while ago here
Upvotes: 2