Building a Lync IM Conversation Window: Introduction (Part 1 of 5)
Summary: This article is the first in a series of five articles that describe how to build a Microsoft Lync 2010 IM conversation window that features a spelling checker, and then add the spelling checker to the conversation window.
Applies to: Microsoft Lync 2010 SDK | Microsoft Lync 2010 | Microsoft Lync 2010 API
Published: March 2011 | Provided by: John Austin, Microsoft | About the Author
Contents
Introduction
Development Scenario
Lync 2010 API IM Types
Conversation Logic
Code Details
Summary
Additional Resources
This article is the first in a five-part series of articles about how to build a Lync 2010 IM conversation window.
Building a Lync IM Conversation Window: Window Control Event Handlers (Part 2 of 5)
Building Lync IM Conversation Windows: Helper Methods (Part 3 of 5)
Building Lync IM Conversation Windows: Lync 2010 API Event Handlers (Part 4 of 5)
Building Lync IM Conversation Windows: Helper Classes (Part 5 of 5)
Introduction
The logic appearing in Adding Lync 2010 Features to Your Application (Part 2) shows how to initialize a Lync 2010 client, and then sign a user in to Lync 2010 through a third-party application. The C# code appearing in this article can be used to build a custom IM conversation window. The code includes method calls and shows where to position each method calls so the sample application processes text as it is typed in the UI. For more information about integrating Lync 2010 features into your application and then initializing and signing in to Lync 2010, see Adding Lync 2010 Features to Your Application (Part 2).
Part 1 includes the following information:
Lists Microsoft Lync 2010 API classes, methods, properties, and enumerations that are used to build the IM conversation window.
Shows how to sign in to Lync 2010, find a contact, and discover the contacts feature that helps participants join an IM conversation.
Shows how to register for events that are associated with starting a new conversation.
Building a Lync IM Conversation Window: Window Control Event Handlers (Part 2 of 5) discusses the Microsoft Windows Presentation Foundation (WPF) window that is created to implement the Lync 2010 API logic and types. Building Lync IM Conversation Windows: Helper Methods (Part 3 of 5) discusses helper methods that are added to the IM conversation window. The helper methods start a conversation, add contacts, send messages, and change control properties for the IM conversation window. Building Lync IM Conversation Windows: Lync 2010 API Event Handlers (Part 4 of 5) discusses Lync 2010 API event handlers and callback methods. Building Lync IM Conversation Windows: Helper Classes (Part 5 of 5) shows how to add a spelling checker to the IM conversation window.
Each article in this series uses code from a WPF sample application that includes a conversation window, a network credential window, and the MSDNArticleIM.ClientModel and MSDNArticleIM.BingSpellChecker helper class. These classes are part of the MSDNArticleIM namespace.
Development Scenario
The development scenario includes a Microsoft Word Repository Client application together with a WPF conversation window. Lync 2010 API is used to add various IM features that appear in the conversation window.
Users can access and update the documents stored in the Word Repository Client application. The SQL table appearing in the repository includes a column that lists the SIP address for all authors. The co-author properties in all Word documents include a corresponding SIP address. An author can be invited to an IM conversation that is hosted by the application by using the SIP address. The repository also functions as a contact list where each contact exists in the context of the documents that they author.
The following table lists preliminary design features.
Feature |
Description |
Preliminary design issue |
---|---|---|
Spelling checker |
Verifies text at it is typed in conversation window. |
Spelling checker feature cannot plug-into a Lync 2010 conversation window. |
Dock Lync 2010 conversation window in the application to integrate IM conversations and the spelling checker. |
IM conversation is integrated with the application. A text-entry control is used to type text in the conversation window. |
Users did not accept the design after they used the prototype. An application that presents alternate text-entry fields in a form is not an ideal scenario. |
Users must converse with document author by using IM. |
If the Lync 2010 conversation window is docked, users share a desktop, processes, and monitor screens. |
Application requirements specify that these features must be hidden from user. |
To avoid the issues appearing in the previous table, Lync 2010 API can be used to add a full-featured IM UI. The Lync 2010 API solution requires more code than the preliminary design option that starts the Lync 2010 conversation window with Automation.StartConversation(). However, the Lync 2010 API solution creates a scenario where various features can be used. For example, monitor user keystrokes as they are typed in the IM user interface. What else can be done with IM text on behalf of the user if application logic can access IM text as it is typed in the IM user interface?
Figure 1 shows the WPF conversation window that is built to work with the Word Repository Client application.
Figure 1. WPF conversation window
Lync 2010 API IM Types
Various Lync 2010 API classes are used to create the Word Repository Client application. The following table lists the Lync 2010 API classes that you get, events that you register for, and methods that you call to start an IM conversation. The types appear in the order that they are used.
Class |
Member type |
Name |
Description |
---|---|---|---|
Event |
User signs in to Lync 2010. |
||
Method |
ContactManagerGetContactByUri(string) |
Returns a contact. |
|
Method |
ContactManagerBeginLookup(string, AsyncCallback, object) |
Starts a lookup operation with a partial or complete name. |
|
Method |
Gets the result of a lookup operation. |
||
Event |
Presence or IM capability has changed for a contact. |
||
Method |
Get presence, source network, and IM capabilities for a contact. |
||
Event |
New conversation is ready. |
||
Event |
Delete a conversation. |
||
Method |
Create a new conversation. |
||
Event |
Participant is added to the conversation. |
||
Method |
Invite a contact to the conversation. |
||
Event |
Participant starts or stops typing text. |
||
Event |
IM capabilities for a participant change. |
||
Event |
A new IM message is received by a participant. |
||
Method |
InstantMessageModalityBeginSetComposing(boolean, AsyncCallback, object) |
Sends current typing activity of a user. |
|
Method |
Send IM text to conversation participants. |
||
Method |
Complete operation and handle exceptions. |
||
Method |
Complete operation and handle exceptions. |
InstantMessageModality class members are discussed in Building a Lync IM Conversation Window: Window Control Event Handlers (Part 2 of 5). The next section in part 1 discusses how to start a new conversation.
Conversation Logic
The logical flow of code execution in a custom IM conversation window appears in Figure 2.
Part 1 discusses the top three sections that appear in Figure 2. Building a Lync IM Conversation Window: Window Control Event Handlers (Part 2 of 5) discusses the bottom two sections together with how to use the spelling checker feature before it is sent to other conversation participants.
Figure 2. IM conversation flow
The next procedure shows how to start an application that manages an IM conversation.
To start the application
Ensure that the conversation participant is signed in to Lync 2010.
Get a Contact class instance that represents the user who is to be invited to the conversation.
Confirm whether the user is available to join the IM conversation and if they are using a device that can participate in the conversation. For example, the user may be signed in to Lync 2010 on a unified communications desktop telephone that cannot send or receive IM text.
Get the ConversationManager class instance by reading the ConversationManager property of the LyncClient class, and then register for the ConversationAdded event on the conversation manager.
If the user is available, create a new Conversation class instance that represents the IM conversation, and then register for events on the conversation.
Use the new Conversation class instance to invite the user to the conversation by calling AddParticipant.
Code Details
The next section shows how to implement the steps appearing in the previous procedure.
Find a Contact
There are several ways that your application can get the Contact instance that represents the user who is to be invited to the conversation. If you have the user’s SIP URI, call the GetContactByUri method. It is also possible to search for the contact if you have a partial name, a telephone number, or a distribution group name. Call the BeginLookup method, and then call EndLookup to get the contact or group. Finally, search for a contact or group by using the BeginSearch and EndSearch methods.
BeginLookup
BeginLookup is an asynchronous method that returns results of a lookup operation after the EndLookup method is called. The EndLookup call should appear inside the callback method that is supplied to the BeginLookup method. EndLookup blocks the UI thread code from the moment that it is called until the lookup operation is completed. By using the callback method, EndLookup is not called until after the operation is complete because the callback method itself is not called until the lookup operation is completed. The UI code continues to run while the lookup operation runs.
The following example finds a Contact instance for Claus Hansen.
_LyncClient.ContactManager.BeginLookup(“Claus Hansen”, LookupCallback, null);
The following example finds a Contact instance for the first person found whose name starts with "Claus."
_LyncClient.ContactManager.BeginLookup("Claus", LookupCallback, null);
The following example finds a Contact instance for the person whose work telephone number exactly matches the TEL URI that is supplied to the lookup method. If the supplied TEL URI does not resolve to a person in your organization’s Active Directory store, a Contact instance that represents a telephone endpoint is returned.
_LyncClient.ContactManager.BeginLookup("TEL:+15550199", LookupCallback, null);
When the results of a lookup operation are available, the following example is called by Lync 2010 API.
private void LookupCallback(IAsyncResult ar)
{
try
{
object foundItem = _LyncClient.ContactManager.EndLookup(ar);
if (foundItem.GetType().Name == "Group")
{
Group foundGroup = foundItem as Group;
MessageBox.Show("Group found " + foundGroup.Name);
}
else
{
Contact foundContact = foundItem as Contact;
}
}
catch (ItemNotFoundException)
{
MessageBox.Show("Lookup returned no results");
}
}
GetContactByUri
The GetContactByUri method takes a SIP or TEL URI and then returns a Contact instance. A contact is returned even if a telephone number (TEL:+15550199) for the person is passed. The contact that is obtained represents the person who is located at a telephone endpoint. If you pass a SIP (SIP:danh@contoso.com), then a contact that represents a device endpoint is passed. In either case, the endpoint may not be capable of joining the conversation even though the person is available. The Contact instance provides provides information that identifies the participant’s capability to join the conversation.
The following example returns a Contact instance when the SIP URI is known.
Contact _Contact = _LyncClient.ContactManager.GetContactByUri("claush@contoso.com");
As long as the SIP URI is formed correctly, a Contact instance is returned. The contact instance may resolve to a contact that signed in to a non-federated IM client. A contact in this kind of state can participate in an IM conversation but cannot display formatted IM text.
Join the Conversation
After the targeted contact is identified, you must confirm whether the contact can participate in an IM conversation. The contact may be unable to participate in the following scenarios.
The user represented by the contact may be signed in to Lync 2010 with a device that cannot capture or display IM text.
The user may not be available. For example, the user can be signed out or in a do-not-disturb state.
Note
To add members of a distribution group to the conversation, iterate on the group as a collection of contacts. Each contact is individually added to the conversation. A nested distribution group can be expanded to get the contacts in the nested group.
To add the members of a CustomGroup, FrequentContacts, or FavoriteContacts group to a conversation, iterate on the group and then add each member individually.
If a contact cannot participate in an IM conversation, you can assess the contact’s state. To discover the state of the user’s capability to participate, read the contact information ContactInformationType.Capabilities property. Capabilities returns a collection of contact capabilities. One kind of capability is named RenderInstantMessage.
The following example gets the capabilities of a Contact instance, registers for changes in that contact’s information, and then examines the RenderInstantMessage capability. If zero, false is returned to the calling code.
_Contact.ContactInformationChanged += _Contact_ContactInformationChanged;
List<ContactInformationType> wantedInformation = new List<ContactInformationType>();
wantedInformation.Add(ContactInformationType.Capabilities);
boolean _FormatMessageAsText = canParticipateInIM
(_Contact.GetContactInformation(wantedInformation));
private static bool canParticipateInIM(IDictionary<ContactInformationType, object> contactInfo)
{
// If RenderInstantMessage capability value is zero, it cannot receive a formatted IM.
// Contact may be blocked, offline, or on a non-IM device. This value can change after the contact signs in somewhere else.
if (0 == ((ContactCapabilities)contactInfo[ContactInformationType.Capabilities] & ContactCapabilities.RenderInstantMessage))
{
return false;
}
return true;
}
A warning message can be displayed if a contact’s ability to display instant messages changes. By using this kind of message, a user can be notified that another user can now join the IM conversation. To get the notification, register for the ContactInformationChanged event on the person’s Contact instance.
The following example handles the event by checking the new state of the contact’s capability to join an IM conversation. When the contact can participate in an IM conversation, a warning message appears.
void selectedContact_ContactInformationChanged(object sender, ContactInformationChangedEventArgs e)
{
Contact changedContact = sender as Contact;
if (0 != ((ContactCapabilities)changedContact.GetContactInformation(ContactInformationType.Capabilities) & ContactCapabilities.RenderInstantMessage))
{
string contactName = string.Empty;
contactName = changedContact.GetContactInformation(ContactInformationType.DisplayName).ToString();
MessageBox.Show(contactName + " can now render IM");
}
}
Summary
Part 1 discussed the following topics that show how to embed an IM conversation in an application.
Lync 2010 API types that are used to add the spelling checker feature to an application.
General logic flow that adds the spelling checker to the application.
Find a contact by using a SIP address, TEL address, or a first and last name.
Determine whether a contact can join an IM conversation.
In part 2, the following coding tasks are discussed:
Register for events on a new conversation object.
Invite a contact to a new conversation.
Register for conversation participant and IM modality events.
Build a scrolling text box to display the IM conversation.
Send a typing activity status to remote conversation participants.
Use the spelling checker to check IM text before the IM is formatted and sent to participants.
Send IM text.
Render IM text from other participants.
Additional Resources
For more information, see the following resources:
About the Author
John Austin, Microsoft, is a programmer/writer in the Lync client SDK documentation team. He has been writing Microsoft technical documentation for four years. Prior to working for Microsoft, John spent two decades as a software developer.