Silverlight – Showing HTML content “inside” Silverlight – without the WebBrowser control

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).

image

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.

image

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.

image

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!

Small browser window
image

 

Bigger browser window

image

 

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=&lt;%=HttpContext.Current.User.Identity.Name%&gt;" />
              <a href="http://go.microsoft.com/fwlink/?LinkID=149156&amp;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=&lt;%=HttpContext.Current.User.Identity.Name%&gt;" />
              <a href="http://go.microsoft.com/fwlink/?LinkID=149156&amp;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”

image

 

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

Simple Silverlight web browser using iframe

Latest Posts

Popular Posts