Silverlight presence indicator

A while back I published a Silverlight presence indicator control on CodePlex and I thought I’d explain this in more detail here.

The control is nothing more than an integration with the standard OCS presence indicator that comes with Microsoft Office (using Name.dll made famous by SharePoint sites). The integration is done using the Silverlight HTML bridge and javascript.

It’s all very simple and straightforward; the control injects javascript into the page where your Silverlight application is hosted and using these scripts it instantiates a new ActiveX object as well as hooking up the OnStatusChanged event.

if(!IMControl){{ IMControl = new ActiveXObject(\"Name.NameCtrl.1\");

IMControl.OnStatusChange=OCSOnStatusChange;

The function called when the ActiveX object fires a status change event will the use the HTML bridge to call a method in the Silverlight control to update the indicator icon.

function OCSOnStatusChange(name, state, id) {

  eval('{0}.Content.' + callbacks[id] + '.UpdateImage(' + state + ',\"'+ name +'\");');
}

This is made possible by registering the Silverlight control as a scriptable object so it can be called from Javascript.

HtmlPage.RegisterScriptableObject(objectName, this);

The UpdateImage method is the tagged as a ScriptableMember, otherwise it won’t be exposed to the HTML bridge.

[ScriptableMember()]
public void UpdateImage(object state, object name) {
    int stateValue = Int32.Parse(state.ToString());
    string imgName = GetStateIndicatorImage(stateValue, true);
    indicator.Source = new BitmapImage(new Uri(string.Format("/Silverlight.OCS;component/Images/{0}", imgName), UriKind.Relative));
    FireStatusChanged(name as string, stateValue);
}

Now, to get the ActiveX object to display the Communicator panel (where you can initiate chat sessions, see details, etc) we will use the HTML bridge to go in the other direction: From Silverlight to Javascript.

Among the Javascript functions we’ve injected into the page is the OCSOpenUI function, which we will call from Silverlight when we receive the MouseOver event on the indicator icon.

function OCSOpenUI(user, x, y) {    if(IMControl){       IMControl.ShowOOUI(user, 0, x, y);    } }

To call this function, all we need to do is invoke it:

HtmlPage.Window.Invoke("OCSOpenUI", User,x, y);

The coordinates are a bit tricky, as the Office 2010 Communicator panel will function just fine with the standard mouse coordinates. However, previous Office versions require that you locate the exact position of the Silverlight control then adjust for mouse coordinates. This involves using Javascript again to find the location of the control within the HTML page.

if (OfficeVersionCompatibility == Version.Office2007AndOlder) {
    ScriptObject result = (ScriptObject)HtmlPage.Window.Invoke("findPos", HtmlPage.Document.GetElementById(HtmlPage.Plugin.Id));
    int left = Int32.Parse(result.GetProperty("Left").ToString());
    int top = Int32.Parse(result.GetProperty("Top").ToString());
    Point posOnIcon = e.GetPosition(indicator);
    x = left + (int)(pos.X - posOnIcon.X);
    y = top + (int)(pos.Y - posOnIcon.Y);
}

 

In closing…

I’ve skipped a lot of steps here as the source code is freely available and should be fairly easy to understand. Should there be any questions, I’ll be more than happy to explain it in more detail 🙂 Also, should anyone have a better way of doing this, I’d appreciate some feedback.

You can find a compiled version of the control and the source code available here: CodePlex