I have a WPF app. I need to embed a Silverlight app inside it. As I understand the most common way to do this is using of System.Windows.Controls.WebBrowser control (note: my app is wpf not WinForms).
BTW: there’s another way to host a Silverlight app – to use its COM interface (see http://www.codeproject.com/KB/atl/Host_Silverlight_In_ATL.aspx).
So in my WPF app I have a WebBrowser somewhere:
<WebBrowser x:Name="webBrowser">
where I load my html page (let’s assume local htlm page for the sake of simplicity):
private void Window_Loaded(object sender, RoutedEventArgs e)
{
webBrowser.LoadCompleted += WebBrowser_LoadCompleted;
webBrowser.Navigate(new Uri(Path.GetFullPath("HostPage.htm")));
}
private void WebBrowser_LoadCompleted(object sender, NavigationEventArgs e)
{
MessageBox.Show("Silverlight app has loaded");
}
Ok. That’s easy.
Now I want to communicate with the host from the SL-app and with the SL-app from the host.
I understand technics for interoperability between HTML(JS) and Silverlight ( http://msdn.microsoft.com/en-us/library/cc645076%28VS.95%29.aspx ) and between .NET and JS inside WebBrowser.
I can set up WebBrowser.ObjectForScripting with an object (marked with ComVisibleAttribute) and the object will be accessing in JS.
I even can get reference to this object from my embedded Silverlight app:
(ScriptObject) HtmlPage.Window.GetProperty("external");
I also can make some object inside the Silverlight app visible to JS (and probably to host code) via HtmlPage.RegisterScriptableObject(“name”, anObject);
But. The problem is that in all cases I have to deal with some untyped ScriptObject instances.
But I’d like to set up “fully managed code” communication between the host and the SL-app. I mean passing complex structures/classes/delegates, raising event, and so on, i.e. without any “untyped JS-stuff”.
How can I do that?
UPDATE:
ok, it seems that there’s no nice way to do what I want.
So I have to deal with JS-interoperability. But here I have a problem.
From the host I set up ObjectForScripting and SL-app can use it. That means the SL-app gets results from methods of the object set up in WebBrowser.ObjectForScripting:
((ScriptObject) HtmlPage.Window.GetProperty("external")).Invoke("methodName")
But not on the contrary.
In my SL-app I register an object (of type BridgeSl):
m_bridgeSl = new BridgeSl();
HtmlPage.RegisterScriptableObject("bridge", m_bridgeSl);
Then create JS-function in html :
<script type="text/javascript">
var g_bridgeSl = null;
function pluginLoaded(sender, args) {
g_bridgeSl = sender.getHost().Content.bridge;
}
</script>
where pluginLoaded is handler of the SL plugin’s onLoad event:
<object id="slCtrl" data="data:application/x-silverlight-2," type="application/x-silverlight-2" ...>
<param name="onLoad" value="pluginLoaded" />
</object>
Then add function returning this object:
function getBridge() {
return g_bridgeSl;
}
I did all this stuff as I hoped that I can get BridgeSl’s instance inside my host app:
var bridgeSl = WebBrowser.InvokeScript("getBridge");
Actually I get something. It’s an instance of “System.__ComObject”. But when I cast it to dynamic:
dynamic dynBridgeSl = bridgeSl;
I get System.SystemException object with message “The method or operation is not implemented”. Ok, it’s can’t be treated as a dynamic, but what is it then? How to invoke any method on it?
There’s no managed-only interop at this time. The two options you mention (JavaScript interop over the DOM bridge, or COM hosting) are all that exists.
I do commend you for doing your research – you knew everything I was going to say when I clicked on the question!