Sharepoint webpart for Silverlight 2.0

March 31, 2008

Before the last release of Silverlight 2.0 beta 1 embedding a silverlight application in a webpart was a somewhat tedious thing to do. Basically, you had to deploy your silverlight.dll and .xaml file within your Sharepoint solution as well as a bunch of javascript files that are called from your sharepoint webpart to create your silverlight content.

With the last release of Silverlight 2.0 all this steps are no longer necessary and we can easily host Silverlight Applications in Sharepoint Webparts just by including Silverlight controls and deploying .xap files with our solution.

For this example, I’ll create a generic webpart that will be able to load any .xap file accessible at our server. It will have a XapUrl property where we will be able to write a Url where the webpart will search for the xap file. Obviously this means that the .xap file must be deployed in our server, I usually do that by including the file in my Sharepoint Solution and deploying it in the _layouts folder of my server.

So following, is the code of my Silverlight Webpart


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.WebControls.WebParts;
using System.Runtime.InteropServices;
using System.Web.UI;

namespace Examples.SilverLight
{
    public class SilverLightWebpart : System.Web.UI.WebControls.WebParts.WebPart
    {
        private ScriptManager _scriptHandler;
        private System.Web.UI.SilverlightControls.Silverlight _silverlightControl;

        private string _xapUrl = string.Empty;
        [WebBrowsable(true), Personalizable(true)]
        public string XapUrl
        {
            get { return _xapUrl; }
            set { _xapUrl = value; }
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            _scriptHandler = ScriptManager.GetCurrent(this.Page);
            if (_scriptHandler == null)
            {
                _scriptHandler = new ScriptManager();
                _scriptHandler.ID = "ScriptManager1";
                this.Controls.Add(_scriptHandler);
            }

            if (!string.IsNullOrEmpty(_xapUrl))
            {
                _silverlightControl = new System.Web.UI.SilverlightControls.Silverlight();
                _silverlightControl.ID = "Xaml1";
                _silverlightControl.Source = _xapUrl;
                _silverlightControl.Version = "2.0";
                this.Controls.Add(_silverlightControl);
            }
        }



    }
}

Basically what we are doing is adding a ScriptManager and a Silverlight controls to our class. The only things we have to take care of are to ensure that there is only one instance of a ScriptManager in our current page (we do that with the call ScriptManager.GetCurrent(this.Page);) and that we must create the controls in the OnInit event of our webpart instead of the usual CreateChildControls event if not, we will get an exception from ScriptManager.RegisterScriptControl telling “Script controls may not be registered before PreRender

And that’s all, see how simple is now to host silverlight applications in our sharepoint server !


Silverlight 2.0 beta 1 ListBox Databinding and possible bug ?

March 12, 2008

This week I’ve started playing with the new and longly waited Silverlight 2.0 beta 1 libraries. Finally we can develop real world bussiness applications with Silverlight using all the UI controls that this beta release includes.

After doing a couple of HelloWorld samples, I decided to try the DataBinding feature. In theory, it is really simple to databind our controls to the bussiness classes by setting their DataContext property which is something I won’t cover in this post and you can follow this link if you are looking for a nice tutorial on this topic.

What I’ll cover here is a strange issue I found when trying to databind a ListBox control to a simple List<string> data source.

In my XAML code, I’ve simply added a ListBox control and set it’s DataContext property to the databinding I’ll be using:

<ListBox x:Name=”Items” ItemsSource=”{Binding Items, Mode=OneWay}” />

I also set the DataContext property of the list to the object I’ll be using to do the databinding at the codebehind of the control, there’s also a button that will call the AddItem function (see later) of my bussiness class:

public partial class Page : UserControl
{
    private Invoice _invoice = new Invoice();    

    public Page()
    {
        Items.DataContext = _invoice;
        myButton.Click += new RoutedEventHandler(myButton_Click);
    }

    void myButton_Click(object sender, RoutedEventArgs e)
    {
        _invoice.AddItem("this is a new Item!");
    }
}

And here is my business class which I’ve reduced to the list property to keep things simple:

public class Invoice : INotifyPropertyChanged
{
    private List _items = new List();

    public List Items
    {
        get { return _items; }
        set { _items = value; NotifyPropertyChanges("Items"); }
    }

    public void AddItem(string newItem)
    {
        _items.Add(newItem);
        NotifyPropertyChanges("Items");
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanges(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

The interesting part in the above code is the AddItem function. Since I wan’t to be able to add new items in the Items collection and automatically update the UI control responsible for displaying the list of items, I can’t simply call the Items.Add method because we must call NotifyPropertyChanges to get our databinding updated. We could also have created our custom list class that implemented INotifyPropertyChanged interface and took care of this (which is something I will surely do in my applications) but for this example is not necessary.What one would expect to happen with this code is that whenever the button click event is clicked, a new item is added in the “Items” list and the ListBox is updated. However, this is not working this way. What happens is that the item is added in the “Items” list but the ListBox control is not updated, the new item is not showing in the UI at all, futhermore, if we set up some breakpoints right after the AddItem method is called, we will see that the ItemsSource collection of the ListBox control is correctly updated and will contain a new item as it should, but the control is not updating it’s UI.

Finally, if I change the AddItem method of the bussiness class to the following implementation, everything works as expected and the list UI is correctly updated:

public void AddItem(string newItem)
{
    List temp = new List(_items);
    temp.Add(newItem);
    _items = new List(temp);
    NotifyPropertyChanges("ITems");
}

I haven’t still found an explanation of this strange behaviour and would really appreciate if somebody could point me out if there is something I have done wrong or if it’s some kind of bug in the beta 1 library. So any comment regarding this will be appreciated !Thanks for your time and come back again for more interesting topics on the highly expected Silverlight 2.0 release !