.NET桌面应用程序内嵌入Silverlight应用程序以及它们之间的通信

时间:2011-02-08 15:27:51

标签: .net wpf silverlight interop

我有一个WPF应用程序。我需要在其中嵌入一个Silverlight应用程序。据我所知,最常见的方法是使用System.Windows.Controls.WebBrowser控件(注意:我的应用程序是wpf而不是WinForms)。
BTW:还有另一种托管Silverlight应用程序的方法 - 使用其COM接口(参见http://www.codeproject.com/KB/atl/Host_Silverlight_In_ATL.aspx)。

所以在我的WPF应用程序中,我有一个WebBrowser:

<WebBrowser x:Name="webBrowser">

我加载我的html页面(为了简单起见,我们假设本地htlm页面):

    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");
    }

确定。这很容易。
现在我想通过SL-app和主机的SL-app与主机进行通信。

我理解HTML(JS)和Silverlight(http://msdn.microsoft.com/en-us/library/cc645076%28VS.95%29.aspx之间)以及WebBrowser中.NET和JS之间的互操作性技术。
我可以使用一个对象(用ComVisibleAttribute标记)设置WebBrowser.ObjectForScripting,该对象将在JS中访问。
我甚至可以从我的嵌入式Silverlight应用程序中引用这个对象:

(ScriptObject) HtmlPage.Window.GetProperty("external");

我也可以通过HtmlPage.RegisterScriptableObject(“name”,anObject)在JS(也可能是托管代码)中看到Silverlight应用程序中的一些对象;

但是。问题是在所有情况下我都要处理一些无类型的ScriptObject实例。 但我想在主机和SL-app之间建立“完全托管代码”通信。我的意思是传递复杂的结构/类/委托,引发事件等,即没有任何“无类型的JS-stuff”。

我该怎么做?

更新: 好吧,似乎没有什么好方法可以做我想要的。 所以我必须处理JS互操作性。但在这里我有一个问题。 从主机我设置ObjectForScripting和SL-app可以使用它。这意味着SL-app从WebBrowser.ObjectForScripting中设置对象的方法获得结果:

((ScriptObject) HtmlPage.Window.GetProperty("external")).Invoke("methodName")

但不是相反。 在我的SL-app中,我注册了一个对象(BridgeSl类型):

m_bridgeSl = new BridgeSl();
HtmlPage.RegisterScriptableObject("bridge", m_bridgeSl);

然后在html中创建JS函数:

<script type="text/javascript">
var g_bridgeSl = null;
function pluginLoaded(sender, args) {
    g_bridgeSl = sender.getHost().Content.bridge;
}
</script>

其中pluginLoaded是SL插件的onLoad事件的处理程序:

<object id="slCtrl" data="data:application/x-silverlight-2," type="application/x-silverlight-2" ...>
  <param name="onLoad" value="pluginLoaded" />
</object>

然后添加返回此对象的函数:

function getBridge() {
  return g_bridgeSl;
}

我做了所有这些事情,因为我希望我可以在我的主机应用程序中获取BridgeSl的实例:

var bridgeSl = WebBrowser.InvokeScript("getBridge");

其实我得到了一些东西。它是“System .__ ComObject”的一个实例。但是当我把它投射到动态时:

dynamic dynBridgeSl = bridgeSl;

我获取System.SystemException对象,并显示消息“方法或操作未实现”。好吧,它不能被视为动态,但那又是什么呢?如何调用它上面的任何方法?

2 个答案:

答案 0 :(得分:2)

目前还没有托管互操作。您提到的两个选项(DOM桥接器上的JavaScript互操作或COM托管)都存在。

我确实赞扬你做研究 - 当我点击这个问题时,你知道我要说的一切!

答案 1 :(得分:0)

我不完全确定如何在SL应用程序和主机之间传递复杂的结构,但是在引发事件时可能有一个选项是通过URL传递信息。将事件处理程序附加到WebBroswer.Navigated事件,并让该处理程序根据URL中的信息引发主机事件。

例如,我们有一个Silverlight应用程序,它托管在WPF WebBrowser控件中。我们想知道用户何时单击Silverlight应用程序中的“关闭”按钮。我们将事件处理程序附加到WebBrowser.Navigated并解析了URL。我们专门在该网址中查找“closed = true”。如果找到,请关闭整个应用程序(包括WPF主机)。

Silverlight App inside WPF WebBrowser ?