SharePoint ClientContext.List is missing?

The SharePoint Object Model has:

  • SPContext Members
  • SPContext.Current (static)
  • SPContext.Site
  • SPContext.Web
  • SPContext.List

By comparison, the SharePoint Client Object Model only has:

  • ClientContext Members
  • ClientContext.Current (static)
  • ClientContext.Site
  • ClientContext.Web
  • ClientContext.List (AWOL missing!)

Here's one trick I've started using - the current list exists on the page in javascript (ctx.listName)

So using Silverlight's Javascript bridge I'm able to test and pull that value back into Silverlight - without any looping through the ClientContext.Web.Lists.

string listName = string.Format("{0}", HtmlPage.Window.Eval("ctx.listName"));
// using string.Format to take care of null problems
// the ctx.listName looks like a guid

List list = _clientContext.Web.Lists.GetById(new Guid(listName));

 

So taking a step back, this would be the first time I wrote something that uses both client object model at once!

SharePoint 2010 and Silverlight 4.0 Webcam

Tonight's Silverlight play involves Silverlight 4 Web Cam API, and SharePoint 2010 Client Object Model.

SILVERLIGHT 4 WEBCAM API

Silverlight 4's WebCam API is relatively simple:

_captureVideoDevice = CaptureDeviceConfiguration.GetDefaultVideoCaptureDevice();
_captureSource = new CaptureSource();
VideoBrush brush = new VideoBrush();
brush.SetSource(_captureSource);

WebCameraCapture.Fill = brush; // fill rectangle "render" area

var device = _captureVideoDevice.FriendlyName; // check device name during debug
if (CaptureDeviceConfiguration.AllowedDeviceAccess || CaptureDeviceConfiguration.RequestDeviceAccess())
{
    _captureSource.Start();
}

The most interesting part is probably the RequestDeviceAccess call. This call must be initiated in an UI event (click) and will raise the following dialog

clip_image002

 

TAKING SNAPSHOTS

Once the camera is rolling, clicking the button takes a snapshot and saves it back to the document library.

WriteableBitmap bmp = new WriteableBitmap(WebCameraCapture, null);
MemoryStream stream = new MemoryStream();
// didn't want to save as bitmap - convert to JPEG first
EncodeJpeg(bmp, stream);

var fileCreationInfo = new FileCreationInformation();
fileCreationInfo.Content = stream.ToArray();
fileCreationInfo.Url = string.Format("pic_{0}.jpg", DateTime.Now.Ticks);
var _documentLibrary = _clientContext.Web.Lists.GetByTitle("ListName");
var uploadFile = _documentLibrary.RootFolder.Files.Add(fileCreationInfo);
_clientContext.Load(uploadFile);
_clientContext.ExecuteQueryAsync(delegate{}, delegate{});

In this screenshot I've added the Silverlight web part on top of the asset library list.

clip_image004

 

WHAT ABOUT VIDEO?

This is where we'll probably get stuck. Silverlight 4 has API to access camera, and we're able to save bitmap data from the camera, but Silverlight 4 lacks the client side encoding libraries capable of saving the bitmap stream back into any meaningful format such as MPEG.

Until Microsoft provides one, or some 3rd party writes one, saving video back to SharePoint document library is going to get put on hold.

REFERENCE

The code for converting to JPEG I copied from http://stackoverflow.com/questions/1139200/using-fjcore-to-encode-silverlight-writeablebitmap.

DOWNLOAD

The Silverlight Camera XAP binaries are in this XAP file 

The Silverlight Camera Sandbox Solution and read me file 

 

INSTALLATION

  1. Upload the XAP file to a document library, copy the URL to this XAP file.
  2. Create a document library to host all the pictures, open the web part zones on the view page and insert a Silverlight Web Part - use the URL to XAP from step 1.
  3. Remember to refresh the page to see new pictures - the list doesn't refresh automatically.  You can switch on async properties in the web part editor for the pictures and it will update itself on a timer basis.

UPDATE

20 July - Added sandbox solution WSP and a simple read-me file

SharePoint 2010 - Update All List Items SharePoint Designer Workflow Action

Out of the box - SharePoint provides quite a few different Workflow Actions, but strangely missing was a Workflow action that can loop through and update all items within a list.

clip_image002

Figure: Update List Item (but only works with one item)

Further to my shock was that someone out there (cough Codeplex) hasn't written one yet. So last night I sat down and start to code.  There will be another article about coding and packaging a SharePoint Workflow Activity, but right now, I need to shove my baby out the door.

UPDATE LIST ITEMS v1.0 INSTALLATION

Everything in one WSP file: grab it here

The package includes 3 objects:

  • WorkflowActivity.dll - goes in the GAC
  • WorkflowActivity.ACTIONS - goes into <SharePointRoot>\TEMPLATE\1033\Workflow\WorkflowActivity.ACTIONS
  • <authorizedType> entry needed in Web.Config - I've included a Web Application feature that will do this

To activate the web application feature

clip_image004

 

UPDATE LIST ITEMS v1.0 USERS GUIDE

clip_image006

In SharePoint Designer, select the "Update All List Items" action from the menu

clip_image008

Or just do the inline typing

clip_image010

There is only 1 dialog for this action - I cheated and reuse the dialog from Update Item Workflow Action

clip_image012

Unfortunately, because I cheated and use Microsoft's dialog - it won't let us finish without specifying a List Item - hence I use the sentence "Update all items in this list (ignore list item)" - sorry - hope that was clear.

clip_image014

OK and trigger the workflow

clip_image016

 

SUMMARY NOTES

  1. In SharePoint, a workflow can not trigger itself. So even though I have the workflow set against this list - it is only run on the last item.
  2. And because this is version 1 (v1.0) there's some really complex looking code for setting "People or Group" values. So I'm not sure if this works 100% in my implementation.
  3. Obviously, if your list is extremely large you are on your own :-)
  4. One other scenario this opens up is the facility to have a site workflow "trigger" a second workflow set on a particular list (remember - workflow can't trigger itself).

Silverlight - merging detached object back to the attached data context

This is a short post on something that we did in the days of Silverlight 2~3, before we have RIA services.

Consider two method signatures on the service:

  1. public EntityPerson GetPerson(object key);
  2. public void SavePerson(EntityPerson person);

Silverlight gets an EntityPerson object, exposes it via the ViewModel for databinding.  The user hits the save button, and the data is coming back through the wire.

It comes back to SavePerson, but the object is disconnected.

The way we've always done this is this way:

//Update or Insert person:
if (entityPerson.PersonID > 0) //update 
{
    EntityKey key = entities.CreateEntityKey("tblPerson", entityPerson);
    object originalItem;
    if (entities.TryGetObjectByKey(key, out originalItem))
    {
        // merge changes from the client back to the dataset
        entities.ApplyPropertyChanges(key.EntitySetName, entityPerson);
    }
}
else//insert new 
{
    entities.AddObject("tblPerson", entityPerson);
}

ApplyPropertyChanges works very well and takes a lot of the work out of our hands.  You can attach a very simple conflict detection if you have a Timestamp field, and by setting the ConcurrencyMode=Fixed.

Saving Changes and Managing Concurrency
How to: Manage Data Concurrency in the Object Context
Flexible Data Access With LINQ To SQL And The Entity Framework

I was recently involved in a short discussion on this topic, and was intrigued to go digging and get to the bottom of it all.  Hope these links help someone :-)

Silverlight Unit Testing - adding a timeout to EnqueueConditional

Since a lot of Silverlight work is asynchronous in nature, the Silverlight testing framework has many helper functions to essentially do "non blocking wait until something happens"

The curious one to me is EnqueueConditional(Func<bool> conditionalDelegate

This one essentially waits until the condition is true - so you can call a method to populate your view model with data, and then wait until data.Count > 0

But the method has no support for timeout.  It can, and will, hold the unit testing framework in progress forever.

Here's my little tweak to the method.

        public override void EnqueueConditional(Func<bool> conditionalDelegate)
        {
            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = new TimeSpan(0, 0, 5);
            timer.Tick += delegate
            {
                // remember to stop timer or it'll tick again
                timer.Stop();
                throw new TimeoutException();
            };
            EnqueueCallback(delegate
            {
                timer.Start();
            });
            base.EnqueueConditional(conditionalDelegate);
            EnqueueCallback(delegate
            {
                timer.Stop();
            });
        }

Here's the unit test to go with it

        [TestMethod]
        [TestProperty("TestCategory", "Silverlight")]
        [Asynchronous]
        [ExpectedException(typeof(TimeoutException))]
        public void Test_Timeout()
        {
            EnqueueConditional(delegate
            {
                // return?  never!
                return false;
            });

            EnqueueTestComplete();
        }

And one more tweak in the App.xaml.cs

        private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
        {
            if (e.ExceptionObject is TimeoutException)
            {
                e.Handled = true;
                // stop any timeoutexception here or it'll bubble to the DOM
                return;
            }

            ...
        }

Here's the result picture:  Running just slightly over 5 seconds.

image

 

Updated: added a result picture.