Archive

Posts Tagged ‘sharepoint client object model’

Integrating Silverlight and Webcams with SharePoint 2010

January 11, 2011 2 comments

I’ve been working a lot with webcams and the SharePoint client object model and have read a number of postings on the subject. I thought I’d try and put one together which brings all the relevant components together to cover the following scenario.

 

Scenario

 

image

SharePoint picture library including the Silverlight webcam web part

To create a SharePoint web part which enables a user to turn on their web cam and allow them to take a picture then save the picture back into a picture library.

To achieve this I have create a fairly simple Silverlight application using the new webcam capabilities now available in Silverlight 4.

When the picture is captured the resulting picture is stored wihtin a WriteableBitmap. I have used an open source assembly (FJ.Core) to convert this into a more appropriate Jpeg.

Finally I hook into SharePoint using the client object model available in SharePoint 2010 and save the Jpeg back into the picture library

 

Walk through.

 

Create a standard Silverlight 4 application and add the following reference dll’s

  1. FJ.Core (for JPeg encoding)
  2. SharePoint’s client object model dll’s
    (Note. You can find these dll in the 14 Hive layouts\clientbin directory)
      a. Microsoft.SharePoint.Client.Siverlight
      b. Microsoft.SharePoint.Client.Silverlight.Runtime
      

    Notes on MVVM
    In my example I have stuck with MVVM (Model View ViewModel)  checkout silverlight.net for more information On MVVM. I have a couple of base classes which I find useful when working with MVVM, One for handling commanding with delegates ‘DelegateCommand.cs’ and ‘MVVMBase.cs’  to handle some standard stuff in your model objects just i.e. NotifyChanged helper methods etc.

Changes to APP.XAML

Open the App.axml.cs file and add a
Using Microsoft.SharePoint.Client;
 
Add the following code to the StartUp  method

//Sharepoint context binding
ApplicationContext.Init(e.InitParams,
System.Threading.SynchronizationContext.Current);

The above ensures the ApplicationContext gets initialised with the same init. Paramaters and synchronizationCotext as the current thread.

 

Main.XAML

I have left the default Silverlight page created in a new project as MainPage.axml.

The first thing to note that this usercontrol has a resource loading the associated viewModel class and is set as the default context of the control.

    <UserControl.Resources>
        <local:MainViewModel x:Key="viewModel" d:IsDataSource="True"/>
    </UserControl.Resources>
    <UserControl.DataContext>
        <Binding Source="{StaticResource viewModel}"/>
    </UserControl.DataContext>

 

In this xaml file I layout a grid with 2 columns and 2 rows. The first row comprised of a rectangle which will get filled with the videobrush which has a source of the web cam and the image on the right hand side gets bound to a WriteableBitmap which is a snapshot taken when the user takes a pic.

A couple of buttons are added to Start the cam, Take a picture then save to sharepoint. To avoid code behind these are all bound to appropriate commands.

 

MainViewModel.CS


All the interesting stuff is in a single viewModel class ‘MainViewModel.cs’

First thing to note is this class inherits from my MVVMBase.cs which gives access to a helper method 

public void NotifyPropertyChanged(string propertyName)

 

I have a few properties which get bound to objects over in Main.axml which are

  1. CapturedImage – the image object binds its source to this. This is the actual picture taken
  2. VideoBrush – the rectangle object binds its fill to this. This is the web cam
  3. Commands : StartCommand, TakePictureCommand and SaveToSharePoint command are bound to their respective buttons

     
    The constructor

    In addition to wiring up the command objects the constructor initialises the CaptureSource object and associates a delegate to the CaptureImageCompleted event. This simply grabs the image capture and stores this to a WriteableBitmap object ‘capturedImage’. I then call a helper methods ‘RefreshCommandStatus’ which causes the command object’s ‘canExecute’ methods to fire resulting in the buttons being enabled or disabled appropriately.  For example if the web cam has not yet been started then the Take Picture button shall remain ‘disabled’

Start the cam

if (_captureSource != null)
     {
         if (_captureSource.State != CaptureState.Stopped)
         {
             _captureSource.Stop(); // stop whatever device may be capturing
         }

         // create the brush
         VideoBrush = new VideoBrush();                
         VideoBrush.SetSource(_captureSource);

         // request user permission and display the capture
         if (CaptureDeviceConfiguration.AllowedDeviceAccess || 
CaptureDeviceConfiguration.RequestDeviceAccess()) { _captureSource.Start(); } } RefreshCommandStates();

Starting the web cam is simple…

Firstly check the cam is initially stopped by looking at the ‘State’ property of _CaptureSource. If it isn’t already stopped then stop it.

Then create a VideoBrush object and set its source to reference the webcam. (This is bound to the Fill property of the rectangle object in Main.axml)

Then you need to attempt to start the cam but you need to wrap this around a couple of checks. Either the user has already specified that the web cam can be used by this application or you can ask Silverlight to ask the user now

imagePrompt displayed to user when attempting to start the cam. 

I then call the refreshcommandstates method to update the status of the buttons. Resulting in the ‘Start Cam’ button being disabled and the ‘Take picture’ button being enabled.

Take a picture

This is the rocket science bit (not!) Just call the  capturesource.CaptureImageAsync method. Because I wired a delegate up in the consturctor when this event has completed an asyncrounous method gets called when the work has been done and the image is saved down to my writeable bitmap property. Binding of the image object ‘source’ property in Main.axml will automaticlally be notified of this change and therefore display the captured image.

 <Image x:Name="takenPicture" Source="{Binding capturedImage}" />

Save picture

To avoid unnecessary requests back and forth to your SharePoint server you can pipe all your requests together such i.e. get web, get list and create item. When your done you then execute all the queries async fashion. Then, with call back delegates you can handle the results ‘Success’ or ‘Failure’ (Success hopefully).

So…

Initiate spClientConext – Ok I hard coded http://sp2010 but you would be best to pass this stuff in dynamically via your web part.

spClientContext = new sp.ClientContext("http://sp2010");

 

Get the appropriate document library. In this case its called ‘pictures’ which is a standard SharePoint picture library

 

spPictureList = spClientContext.Web.Lists.GetByTitle("pictures");

 

Then I create a new FileCreationInformation object. Here I specifiy some properties the main ones are ‘Content’ which is a stream, in this case I convert the writeablebitmap to a Jpeg then into a memory stream, see the helper methods ‘pictureStream’ and ‘EncodeJpeg’

The next property is Url. To ensure I gave this something unique I just used the TimeOfDays.Ticks property but you could prompt the user for a filename.

 

//Create the FileCreationInformation object
                FileCreationInformation fci = new FileCreationInformation();
                fci.Overwrite = true;
                
                fci.Content = pictureStream().ToArray();
                fci.Url = DateTime.Now.TimeOfDay.Ticks + ".jpg";

                //Add to picture library
                spPictureList.RootFolder.Files.Add(fci);

Then I add the FIleCreationInformation object to the picture library’s rootFolder

Finally calling the ExectueeQueryAsync method. When the work is done either my saveSucceeded or saveFailed delgates will be called.


SaveSucceeded

Because this occurs on another thread from the UI thread you need to make sure your call back methods don’t try and access UI objects directly.

By running the code within the Dispatcher I can safley reference objects available in the UI thread. In this case I display a messagebox to the user, then I clear the capturedImage object to allow the user to take another picture.

I also disabled the save button just before the async. Method was  called then enabled it again on completion. Because this is running async. You cant be sure how long the operation will take and  you don’t want the pesky impatient user clicking save again :)

Running it

In this case I simply uploaded the compiled XAP file to a SharePoint document library then used the out of the box SharePoint Silverlight web part. But it would be a better idea to package up your own web part (See previous posting Deploying a silverlight application to SharePoint). This will allow you to pass in dynamic parameters for the library name and site url and not hardcode things like I did in this example.

Download Source Code Here

Follow

Get every new post delivered to your Inbox.