Karine Bosch’s Blog

On SharePoint

Walkthrough 2 – Hosting Silverlight 3 in a Content Editor Web Part


In this sample I’m going to explain how you can host a Silvelright 3 application from within a SharePoint Content Editor Web Part. I got the idea from this blog post. This sample shows no new techniques but builds on the Job Opportunity sample from walkthrough 1 and is the plumbing between the samples about Job Opportunity and Job Application. 

The Silvelright application displays the different job opportunities in an attractive way. Visitors of the portal can then scroll through the job opportunities. Clicking on one of the opportunities will bring the visitor to a page where he/she can apply for the job (wich will be detailed in a 3th walkthrough).

You can download the sample code here.

Step 1 – The Silverlight application

As with most of the Silverlight applications that I host in SharePoint, I pass the URL of the SharePoint site and eventual other data to the Silverlight application using the InitParams property. For this web part I pass the SharePoint URL, the name of the SL Job Opportunities list and the name of the SL Job Application list with the InitParams property.

The user interface of the Silverlight application consists of an Accordion control of the Silverlight Toolkit. One of the advantages of using the accordion control is that you can bind an object collection to it.
The HeaderTemplate of the accordion control will display the title of each job opportunity. The DataTemplate of the accordion control consists of a StackPanel rendering the job description, the offer, the required skills.
There is also an Apply TextBlock that is used as a hyperlink to navigate to the New form of the SL Job Application list (cfr. Walkthrough 3).

<UserControl x:Class="JobOpportunities.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
    Width="600" Height="380">
    <UserControl.Resources>
        <Style x:Key="ContentLabel" TargetType="TextBlock">
            <Setter Property="Margin" Value="2" />
            <Setter Property="Width" Value="550" />
            <Setter Property="Height" Value="20" />
            <Setter Property="FontFamily" Value="Trebuchet MS" />
            <Setter Property="FontSize" Value="12" />
            <Setter Property="Foreground" Value="White" />
            <Setter Property="TextDecorations" Value="Underline" />
            <Setter Property="TextAlignment" Value="Left" />
            <Setter Property="VerticalAlignment" Value="Center" />
            <Setter Property="TextWrapping" Value="Wrap" />
        </Style>
        <Style x:Key="ContentData" TargetType="TextBlock">
            <Setter Property="Margin" Value="15,2" />
            <Setter Property="Width" Value="520" />
            <Setter Property="Height" Value="40" />
            <Setter Property="FontFamily" Value="Trebuchet MS" />
            <Setter Property="FontSize" Value="12" />
            <Setter Property="Foreground" Value="White" />
            <Setter Property="TextAlignment" Value="Left" />
            <Setter Property="VerticalAlignment" Value="Top" />
            <Setter Property="TextWrapping" Value="Wrap" />
        </Style>
    </UserControl.Resources>
        <Canvas x:Name="LayoutRoot" Background="White" Width="600" Height="380" >
            <Border Width="600" Height="380" BorderBrush="Black" BorderThickness="0">
                <toolkit:Accordion x:Name="JobAccordion" Width="590" Height="370" Margin="5,5">
                <toolkit:Accordion.Background>
                    <LinearGradientBrush x:Name="borderLinearGradientBrush" MappingMode="RelativeToBoundingBox"
                                     StartPoint="0,0" EndPoint="1,1">
                        <LinearGradientBrush.GradientStops>
                            <GradientStop Color="#FF4F7189" Offset="0"/>
                            <GradientStop Color="#FF244E6D" Offset="0.525"/>
                            <GradientStop Color="#FFA9B9C5" Offset="1"/>
                        </LinearGradientBrush.GradientStops>
                    </LinearGradientBrush>
                </toolkit:Accordion.Background>
                    <toolkit:Accordion.HeaderTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding JobTitle}" Margin="5" Width="500" Height="25" 
                                       FontFamily="Trebuchet MS" FontSize="14" FontWeight="Bold"
                                       TextAlignment="Left" VerticalAlignment="Center" />
                        </DataTemplate>
                    </toolkit:Accordion.HeaderTemplate>
                    <toolkit:Accordion.ContentTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
                            <StackPanel.Background>
                                <LinearGradientBrush x:Name="borderLinearGradientBrush" MappingMode="RelativeToBoundingBox"
                                     StartPoint="0,0" EndPoint="1,1">
                                    <LinearGradientBrush.GradientStops>
                                        <GradientStop Color="#FF4F7189" Offset="0"/>
                                        <GradientStop Color="#FF244E6D" Offset="0.525"/>
                                        <GradientStop Color="#FFA9B9C5" Offset="1"/>
                                    </LinearGradientBrush.GradientStops>
                                </LinearGradientBrush>
                            </StackPanel.Background>
                                <TextBlock Text="Description:" Style="{StaticResource ContentLabel}" />
                                <TextBlock Text="{Binding Description}" Style="{StaticResource ContentData}"  />
                                <TextBlock Text="We offer:" Style="{StaticResource ContentLabel}" />
                                <TextBlock Text="{Binding WeOffer}" Style="{StaticResource ContentData}"  />
                                <TextBlock Text="Required skills:" Style="{StaticResource ContentLabel}" />
                                <TextBlock Text="{Binding Skillstring}" Style="{StaticResource ContentData}"  />
                                <TextBlock Text="Apply" Width="50" Height="25" Foreground="White" HorizontalAlignment="Left" 
                                           MouseEnter="TextBlock_MouseEnter"
                                           MouseLeave="TextBlock_MouseLeave"
                                           MouseLeftButtonDown="TextBlock_MouseLeftButtonDown" />
                            </StackPanel>
                        </DataTemplate>
                    </toolkit:Accordion.ContentTemplate>
                </toolkit:Accordion>
            </Border>
        </Canvas>
</UserControl>

As in all my samples using the out of the box SharePoint web services, there is a SOAP envelope for retrieving list items via the GetListItems method of the Lists.asmx web service:

        private const string retrieve_envelope = @"<?xml version=""1.0"" encoding=""utf-8""?>
                <soap12:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap12=""http://www.w3.org/2003/05/soap-envelope"">
                   <soap12:Body>
                       <GetListItems xmlns=""http://schemas.microsoft.com/sharepoint/soap/"">
                            <listName>{0}</listName>
                            <query><Query xmlns=""""><OrderBy><FieldRef Name=""Title"" /></OrderBy></Query></query>
                            <viewFields>
                            <ViewFields xmlns="""">
                                <FieldRef Name=""Title"" />
                                <FieldRef Name=""JobDescription"" />
                                <FieldRef Name=""WeOffer"" />
                                <FieldRef Name=""RequiredSkills"" />
                            </ViewFields>
                            </viewFields>
                            <queryOptions><QueryOptions xmlns=""""><IncludeMandatoryColumns>False</IncludeMandatoryColumns></QueryOptions></queryOptions>
                       </GetListItems>
                   </soap12:Body>
                </soap12:Envelope>";

When the Silverlight application loads, the BeginRequest method is called to retrieve the job opportunities from SharePoint. The ProcessResponse method takes care of retrieving the job opportunities from the returned XML into an ObservableCollection of JobData objects, and binding it to the accordeon.

        private void ProcessResponse()
        {
            jobOpportunityList = new ObservableCollection<JobData>();
            XDocument results = XDocument.Parse(responsestring);
            var query = from item in results.Descendants(XName.Get("row", "#RowsetSchema"))
                        select new JobData()
                        {
                            ID = item.Attribute("ows_ID").Value,
                            JobTitle = item.Attribute("ows_Title").Value,
                            Description = item.Attribute("ows_JobDescription").Value,
                            WeOffer = item.Attribute("ows_WeOffer").Value,
                            Skills = RetrieveSkills(item.Attribute("ows_RequiredSkills").Value)
                        };
            foreach (JobData job in query.ToList())
            {
                jobOpportunityList.Add(job);
            }
            JobAccordion.ItemsSource = jobOpportunityList;
        }

When the visitor hovers over a job opportunity, the text becomes underlined, inviting the visitor to click it. If the mouse hovers away, the text is rendered normal again. When the visitor clicks the job opportunity, the underlying JobData object is retrieved to format a URL. This URL indicates the location of the New form of the SL Job Application list and adds the ID of the selected job opportunity to the QueryString

        private void TextBlock_MouseEnter(object sender, MouseEventArgs e)
        {
            ((TextBlock)sender).TextDecorations = TextDecorations.Underline ;
        }
        private void TextBlock_MouseLeave(object sender, MouseEventArgs e)
        {
            ((TextBlock)sender).TextDecorations = null;
        }
        private void TextBlock_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {           
            TextBlock tb = (TextBlock)sender;
            // naviage to SL Job Applications New Item
            if (tb.DataContext != null)
            {
                JobData selectedJob = (JobData)tb.DataContext;
                string applyForUrl = string.Format(apply_url, selectedJob.ID);
                HtmlPage.Window.Navigate(new Uri(applyForUrl, UriKind.Absolute));
            }
        }

Step 2 – Deploy and test

Build the Silverlight application and upload it to a document library in your SharPoint site. There are different deployment possibilities depending on how reusable you want to make your Silverlight application. By uploading it to a document library, the application is available in your site.

On your home page add a Content Editor Web Part and click the Source Editor button in the tool part. Add the following code to it:

<div id="silverlightControlHost" style="width:600;height:400">
        <object data="data:application/x-silverlight-2," type="application/x-silverlight-2"
            width="100%" height="100%">
            <param name="source" value="/XAPS/JobOpportunities.xap" />
            <param name="background" value="white" />
            <param name="initParams" value="url=http://litwareinc.com,list=SL Job Opportunities,applist=SL Job Applications" />
            <param name="minRuntimeVersion" value="3.0.40624.0" />
            <a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=3.0.40624.0" style="text-decoration: none">
                <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight"
                    style="border-style: none" />
            </a>
        </object>
</div>

Don’t forget to set the source argument to the correct location and pass the necessary information into the initParams argument.
You can download the sample code here.

7 Comments »

  1. I think you meant “Content Editor Web Part” not “Content Query Web Part”… those are two entirely different beasts.

    Comment by Mike | March 30, 2010 | Reply

  2. You’re right about that! Corrected now.
    Thanks for the remark,
    Karine

    Comment by Karine Bosch | March 30, 2010 | Reply

  3. Thank you for sharing.
    My Silverlight control tag had width and height set at “100%”. In this case it seems that the webpart _must_ be configured with a fixed height/width, otherwise nothing will be displayed. Might help other users.

    Comment by Half Scheidl | November 30, 2010 | Reply

  4. Thanks Half….I was struggling with this until I saw your reply about setting the wp size. Works perfect now.

    Comment by steve aras | December 10, 2011 | Reply

  5. Fantastic put up, very informative. I ponder why the other specialists of this sector don’t understand this. You must continue your writing. I’m sure, you’ve a great readers’ base already!|What’s Going down i am new to this, I stumbled upon this I’ve discovered It absolutely useful and it has helped me out loads. I hope to give a contribution & help different customers like its aided me. Good job.

    Comment by ssh Hosting | July 12, 2012 | Reply

  6. Hi Karine,

    Have you tried this with Silverlight 5 and Elevated trust when running in browser?

    Something in Sharepoint 2010 seems to be blocking the XAP from being able to go into elevated trust. In the Silverlight App, Application.Current.HasElevatedPermissions is always false.

    Comment by Dave | January 10, 2014 | Reply

    • Hi Dave, unfortunately I didn’t play with Silverlight 5 and SharePoint 2010 anymore. Perhaps you can try to get an answer on the MSDN forum?
      Kind regards,
      Karine

      Comment by Karine Bosch | January 11, 2014 | Reply


Leave a comment