Everyone was VERY excited about the possibility to show HTML content inside Silverlight.
But soon we Silverlight developers realized that it wont work in a inside-browser scenario (if you can call it like that).
It’s a NOOB scenario where we need the browser control, just like the browsercontrol in Winforms (aahhh… the good old days, everything was better ;-)
NOOB = Not Out of Browser scenario
What we want to do is, something like the screenshot below. Stolen from jsFiddle, a great JavaScript framework test tool by the way.
We have a Silverlight application that loads some HTML content (maybe rendered emails) in a small window on the right hand side.
Since there is no webbrowser control, we have to use an iframe and lay that on top of our Silverlight app (argh, ugly, dropped in XHTML1.1 !)
1. Add an iframe to your ASPX or HTML page that hosts your Silverlight app
<%--html body in different color to highlight usage--%> <body style="background: DarkGreen" > <form id="form1" runat="server" style="height:100%"> <div id="silverlightControlHost"> <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"> <param name="source" value="ClientBin/SilverlightApplication2.xap"/> <param name="onError" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="4.0.50401.0" /> <param name="autoUpgrade" value="true" /> <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50401.0" style="text-decoration:none"> <img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/> </a> </object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div> <iframe id="htmlcontentIFrame" style="position:absolute; visibility: hidden; height: 0px; width: 0px; border: 0px" frameborder="0" scrolling="no"/> </form> </body>
Our iframe is in place and ready to load some HTML. Yeah!
2. In our XAML we add a placeholder border, called “borderPlaceHolderIframe”, so that our designer has an idea where the iFrame will be.
3. To make the resizing of the application not a UI layout mess, we add an eventhandler to the SizeChanged event on the Silverlight page. The rest is nothing special in XAML
<navigation:Page x:Class="SilverlightApplication_with_Browser.Page1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" d:DesignWidth="800" d:DesignHeight="600" Title="My Business App" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" SizeChanged="PageSizeChanged">
4. The code is pretty straightforward, and a lot of people have already written about this..
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); IFrameResizeAndShow(); } private void ButtonLoadClick(object sender, RoutedEventArgs e) { string urlToLoad = textBox1.Text; IFrameShowUrl(urlToLoad); } private void PageSizeChanged(object sender, SizeChangedEventArgs e) { IFrameResizeAndShow(); } //`_¸.·´¯.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´ // Helpers //`_¸.·´¯.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´¯`.¸_¸.·´ private static void IFrameShowUrl(string urlToLoad) { if (HtmlPage.Document != null) { HtmlElement myFrame = HtmlPage.Document.GetElementById("htmlcontentIFrame"); if (myFrame != null) { myFrame.SetAttribute("src", urlToLoad); } } } private void IFrameResizeAndShow() { HtmlElement myFrame = HtmlPage.Document.GetElementById("htmlcontentIFrame"); if (myFrame != null) { // this is our placeholder for the designer double placeholderWidth = borderPlaceHolderIframe.ActualWidth; double placeholderHeight = borderPlaceHolderIframe.ActualHeight; double iframeLeft = this.ActualWidth - placeholderWidth; double iframeTop = this.ActualHeight - placeholderHeight; //double checking! if (iframeTop < 0) { iframeTop = 0; } if (iframeLeft < 0) { iframeLeft = 0; } myFrame.SetStyleAttribute("width", placeholderWidth.ToString()); myFrame.SetStyleAttribute("height", placeholderHeight.ToString()); myFrame.SetStyleAttribute("left", iframeLeft.ToString()); myFrame.SetStyleAttribute("top", iframeTop.ToString()); myFrame.SetStyleAttribute("visibility", "visible"); } } }
Now we have our iframe, and it resizes with the browser! Awesome!
Bigger browser window
Ok the layout is crap. But you can do it better!
Small gotcha here: Make sure to place the iframe outside the div hosting the Silverlight object. The navigation iframe is inside the div, because its not supposed to be visible.
BAD
<form style="height: 100%" id="form1" runat="server"> <div id="silverlightControlHost"> <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"> <param name="source" value="BiddingClient.xap" /> <param name="onError" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="4.0.50303.0" /> <param name="autoUpgrade" value="true" /> <param name="Initparams" value="UserAccount=<%=HttpContext.Current.User.Identity.Name%>" /> <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50303.0" style="text-decoration:none"> <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none" /> </a> </object> <iframe style="border-right-width: 0px; width: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px; visibility: hidden; border-left-width: 0px" id="_sl_historyFrame"></iframe> <iframe style="border-bottom: #ffffff 0px solid; position: absolute; border-left: #ffffff 0px solid; width: 30%; height: 50%; border-top: #ffffff 0px solid; top: 80px; right: 20px; border-right: #ffffff 0px solid" id="htmlcontentIFrame" frameborder="0"></iframe> </div> </form>
GOOD
<form style="height: 100%" id="form1" runat="server"> <div id="silverlightControlHost"> <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%"> <param name="source" value="BiddingClient.xap" /> <param name="onError" value="onSilverlightError" /> <param name="background" value="white" /> <param name="minRuntimeVersion" value="4.0.50303.0" /> <param name="autoUpgrade" value="true" /> <param name="Initparams" value="UserAccount=<%=HttpContext.Current.User.Identity.Name%>" /> <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=4.0.50303.0" style="text-decoration:none"> <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style:none" /> </a> </object> <iframe style="border-right-width: 0px; width: 0px; border-top-width: 0px; border-bottom-width: 0px; height: 0px; visibility: hidden; border-left-width: 0px" id="_sl_historyFrame"></iframe> </div> <iframe style="border-bottom: #ffffff 0px solid; position: absolute; border-left: #ffffff 0px solid; width: 30%; height: 50%; border-top: #ffffff 0px solid; top: 80px; right: 20px; border-right: #ffffff 0px solid" id="htmlcontentIFrame" frameborder="0"></iframe> </form>
Otherwise it wont be shown in IE8. Only in IE8 “Compatibility View”
PS
Try to position your iframe with some absolute and percentage values in HTML, so you don’t have to handle the onresize event..
E.g. style = position:absolute; right:20px; top:80px; width:30%; height:50%; border:0px solid #ffffff;
But make sure to test it in different browsers
PPS
Another way to resize the iframe size is to use jQuery and handle the resize() event of the browser window
http://api.jquery.com/resize/
PPPS
Having the website (iframe) in the background and setting the Silverlight object to be windowless is not an option because of performance reasons!!
<param name="windowless" value="true" />
PPPPS
Yes I love this PSessses
References
7 comments:
Hi Peter,
Very nice post!
I'd like to know how to handle the case where the placehorder is draggable or its position in the screen changes with scrolling.
Thanks
-Kin
@kinjin.ng
You have to write some JavaScript for that. Hook into document events like Resize(), scroll() etc...
Hi Peter
Can you please upload the source code.. ?
@Anonymous
The source code should be fine with Silverlight 5. Which part do you mean??
Hi Peter.. very nice.
does the new SL5 in-browser support helps in any way? or every thing is yet the same?
can you please elabrate on the.. PPPS (:
"Having the website (iframe) in the background and setting the Silverlight object to be windowless is not an option because of performance reasons!!
param name="windowless" value="true"
I couldnt really get what you mean..
>>param name=windowless value = true
If you set this to windowsless to true you can display HTML content on top of Silverlight content.
But this makes your page in the browser very slow
param name=windowless value = true
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This Method has some limits.
Can't Input Chinese in HTML
Post a Comment