I’ve not used Silverlight, and I though it might be interesting to try the Silverlight Web Part from SharePoint 2010, so I came up with a little ‘hello world’ project. Using Silverlight, I wanted to:
- Query a SharePoint List for data
- Display that data
Not exactly complicated stuff, but I figured it would be a start. I decided to query a Picture Library, and display the pictures in my web part, changing the displayed image every few seconds. All of this is very achievable with JavaScript or jQuery and the Content Query Web Part (as some sort of variant on the CQTWP I built), so I thought this would be a good comparison.
I created a Silverlight Application Project in Visual Studio, and didn’t create a web site to host it (we’re going to use SharePoint)
I added references to Microsoft.SharePoint.Client.Silverlight and Microsoft.SharePoint.Client.Silverlight.Runtime assemblies in the 14/TEMPLATES/LAYOUTS/ClientBin directory.
In my MainPage XAML, I added an image control:
<Grid x:Name="LayoutRoot" Background="White" Loaded="LayoutRoot_Loaded"> <Image Height="300" HorizontalAlignment="Left" Name="theImage" Stretch="Fill" VerticalAlignment="Top" Width="400" /> </Grid>
Fine – but how do we get the images into it, to display? Well, I started by creating a function to run when the Layout Root was loaded. In it we:
- Get the context of the site (SPWeb)
- Get the ‘Pics’ list (yes, hard coded for this demo)
- Construct a CAML query for the images
- Execute the query asynchronously
public partial class MainPage : UserControl { //class variables SP.ClientContext context; SP.Web myWeb; SP.List myList; SP.ListItemCollection myItems; List<string> files = new List<string>(); System.Windows.Threading.DispatcherTimer myDispatcherTimer; private int _currentIndex = 0; private void LayoutRoot_Loaded(object sender, RoutedEventArgs e) { context = SP.ClientContext.Current; myWeb = context.Web; //Get handle to document library myList = myWeb.Lists.GetByTitle("MyPics"); SP.CamlQuery query = new SP.CamlQuery(); query.ViewXml = "<View></View>"; myItems = myList.GetItems(query); context.Load(myList); context.Load(myItems); context.ExecuteQueryAsync(getRequestSucceeded, getRequestFailed); }
So, next, what to do on Success or Failure? Well, let’s do failure first – show an error message
private void getRequestFailed(object sender, SP.ClientRequestFailedEventArgs e) { Dispatcher.BeginInvoke(() => { MessageBox.Show("Error occured: " + e.Message); }); }
Fine. And on Success? Well, we want to:
- Add our results to a list of image files to show,
- Start a timer that changes the image being shown every few seconds
private void getRequestSucceeded(object sender, SP.ClientRequestSucceededEventArgs e) { Dispatcher.BeginInvoke(() => { //iterate through each file and add file to our list of files foreach (SP.ListItem item in myItems) { files.Add(item["FileRef"].ToString()); } // Do something with our data! myDispatcherTimer = new System.Windows.Threading.DispatcherTimer(); myDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 2000); myDispatcherTimer.Tick += new EventHandler(Each_Tick); myDispatcherTimer.Start(); }); }
That’s fine – but what happens every few seconds (in the Each_Tick delegate?) Well, I wanted a nice ‘Fade Out, fade in’, but this proved tricky. In the end I referred to this example, which showed me how to define my animations in the XAML:
<UserControl.Resources> <Storyboard x:Name="FadeOutAnimation" Completed="FadeOutAnimation_Completed"> <DoubleAnimation Duration="00:00:00.50" From="1" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="theImage" /> </Storyboard> <Storyboard x:Name="FadeInAnimation"> <DoubleAnimation Duration="00:00:00.50" From="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="theImage" /> </Storyboard> </UserControl.Resources>
Fine, so I’ve got animations defined – how do I use them? Well, in my Each_Tick delegate, I incremented the index of the image to be shown, and started the Fade Out animation. Then, when the Fade Out animation completes, it changes the image to be displayed, and starts the Fade In animation:
public void Each_Tick(object o, EventArgs sender) { _currentIndex++; if (_currentIndex == files.Count){ _currentIndex = 0; } FadeOutAnimation.Begin(); } private void FadeOutAnimation_Completed(object sender, EventArgs e) { BitmapImage bmi = new BitmapImage(new Uri(files[_currentIndex], UriKind.Relative)); theImage.Source = bmi; FadeInAnimation.Begin(); }
And that’s it! Sadly, I can’t easily display it – a static image doesn’t do it justice – but that’s all there is to it.
So, my conclusions? Well, I though that querying the list might be tricky – but it was pretty straight forward, to be honest. The hardest part of this was the fading in and out animation, which I suspect is simply down to my lack of experience with SilverLight. I think that if I really knew what I was doing with Silverlight in the same way as I do with jQuery or JavaScript, Silverlight would actually be easier to have created this effect in.
I guess the next question would be feeding in Properties that a user can edit – such as the picture library name – so that the web part is easily reusable.
The real difference is in compatibility. JQuery will work on all major browsers “out of the box”. Silverlight requires a plugin…
I guess the SharePoint world exists mostly within intranets though (yes, I know there are websites based on it in the wild), so the plugin requirement isn’t important.
Yup, that’s my thought too. Also, most of our customers use IE – and I think it’s only a matter of time before MS build Silverlight in…