Walkthrough: Start an IM Conversation (Lync 2010 SDK)
This topic demonstrates how to start an instant messaging conversation. This process involves creating a Conversation instance using the ConversationManager class, creating a participant using the Conversation instance, and connecting to the participant using one of the participant's modalities. In this process, you must handle state change events on both the ConversationManager and Conversation.
The following figure illustrates the classes, methods, and events used in the process of starting an instant messaging conversation.
Starting an Instant Messaging Conversation
The following walkthrough steps obtain a conversations manager and add the conversation.
Walkthrough Steps
Create a callback method that handles the ConversationAdded event.
Create a callback method that handles the ParticipantAdded event.
Get the LyncClient instance and verify that the client is signed in to the server. For information about signing in to Microsoft Lync Server 2010, see Walkthrough: Sign In to Lync with UI Suppressed (Lync 2010 SDK)
Get the ConversationManager class instance by reading the ConversationManager property.
Register for the ConversationAdded event.
Call AddConversation.
Important
If you have a conference Url and you intend to join the associated conference, call JoinConference instead of AddConversation. An instance of Conversation is returned.
Additional walkthrough steps are described in the following section.
Handling Events
The next two procedures are examples of the steps to create event handlers for conversation related events. Examples of the event handler methods are included later in this topic.
ConversationAdded Event
Complete the following steps within a callback method that handles ConversationAdded.
Walkthrough Steps
Check the modality state of the instant message modality on the added conversation. If the modality is ModalityState.Notified then conversation was not started by the local user. For this walkthrough, you handle the event for only the conversation added by the local user.
Tip
The ConversationAdded event is raised when either a local user starts a conversation or a remote user invites the local user to a new conversation.
Register for conversation state change events on the Conversation instance.
Call the CanInvoke method and pass ConversationAction.AddParticipant. Continue walkthrough steps if a true value is returned.
If you can add a participant, get a Contact instance to add to the conversation by calling into GetContactByUri. A contact that resolves to the passed Uri is returned.
Get the instant messaging Modality instance from the Modalities property of the Conversation instance in the data parameter of the ConversationAdded event handler: data.Conversation.Modalities[ModalityTypes.InstantMessagingModality]
ParticipantAdded Event
Complete the following steps within a callback method that handles ParticipantAdded.
Walkthrough Steps
Read the IsSelf property of the added participant exposed by Participant property. The following steps should not be executed for the self-participant.
Get the remote participant InstantMessageModality from Participant by reading the Modalities property collection and returning the InstantMessageModality.
Tip
The instant messaging modality is auto-accepted at both the local and remote endpoints. You do not need to call Connect on this modality. The instant messaging modality is ready to use when you obtain it from the conversation's modalities collection.
Cast the Modality class instance to the InstantMessageModality class to obtain instant messaging receive features.
Register for InstantMessageReceived message received events to catch incoming instant messages from other participants.
Register for participant events on the remote participant.
Send and Receive Messages
As the previous figure illustrates, the walkthrough steps to send an IM message involve many more steps than those you execute to receive and render an instant message from a remote participant. In both cases, you use the InstantMessageContentType enumeration to either set the message format of a message you send or determine the message format of a message you receive. A sent or received message is encapsulated in a generic IDictionary that uses an enumerator of InstantMessageContentType as the key and a formatted message string as the value of the dictionary entry.
Send a Message
Sending an instant message involves setting the local user’s composing state to typing, capturing and sending text, and setting the user’s composing state to idle again. These actions are performed in this sequence and each depends on the completion of the previous step. You should use the System.AsyncCallback method you define for each operation to initiate the next operation in the sequence.
Important
If you send instant message text in a format not supported by the target instant message client, a LyncClientException is raised on your client. The exception message text is "Generic COM Exception. Code is 0x80EF019F. ". To avoid this exception, you send text formatted as plain text. If you use any other formatting, you should enclose EndSendMessage in an try/catch block that catches LyncClientException.
Verify the conversation is active and the conversation instant messaging modality is connected.
When the local user begins to type in the form entry control designated to accept message text, call into CanInvoke, passing ModalityAction. SetIsTyping. If you cannot set this property, skip the next step.
Call BeginSetComposing on the conversation instant messaging modality. Pass true as the first argument.
In the callback invoked by the previous step or upon completion of typing in the form control, instantiate an instance of IDictionary<InstantMessageContentType, string> and add an entry containing a key as enumerator for the message text formatting and value as message text.
Call BeginSendMessage and pass your message dictionary as the first argument. Be sure to pass a System.AsyncCallback method in the second argument.
In the callback invoked after the previous step:
Call EndSendMessage. You must surround this call with a try/catch block, catching the LyncClientException. A remote contact can change their availability to DND or offline at any time. Such an availability change causes this exception to be raised when your message cannot be delivered to the remote contact.
Call BeginSetComposing on the conversation instant messaging modality. Pass false as the first argument.
Receive a Message
The following walkthrough handles the InstantMessageReceived event by getting the message text formatting enumerator for the incoming message and parsing the message text according to the specified formatting.
Get the message contents as IDictionary<InstantMessageContentType,string>by reading Contents.
A single message contains text in one of several formats enumerated by InstantMessageContentType . For each format sent, an entry exists in the dictionary you get from the previous step. Iterate on the dictionary items and assemble a display string based on the format and contents of the dictionary.
Important
Lync 2010 formats IM text as InstantMessageContentType.Html or . Ink. Earlier versions of the client format messages as . RichText. For the best interoperability experience, you should send messages in .PlainText.
Display the resulting string.
Examples
The walkthrough assumes you have created a Windows.Forms object and populated it with a TextBox control for user entry.
Start a Conversation
The following example creates a new conversation by calling into AddConversation on ConversationManager.
private string myRemoteParticipantUri;
private Conversation _Conversation;
//assume example has obtained and signed in to this LyncClient instance.
private LyncClient _LyncClient;
public void StartIMConversation(string participantUri)
{
_LyncClient.ConversationManager.ConversationAdded += ConversationsManager_ConversationAdded;
myRemoteParticipantUri = participantUri;
_Conversation = _LyncClient.ConversationManager.AddConversation();
}
Register for Conversation Events
The following example registers for Conversation events. The Conversation obtained from Conversation is a reference to the new conversation. You can register for events on the Conversation using the Conversation instance.
/// Handles ConversationAdded state change event raised on ConversationsManager
/// <param name="source">ConversationsManager: The source of the event</param>
/// <param name="data">ConversationsManagerEventArgs The event data. The incoming Conversation is obtained here</param>
void ConversationsManager_ConversationAdded(Object source, ConversationManagerEventArgs data)
{
// Register for Conversation state changed events.
data.Conversation.ParticipantAdded += Conversation_ParticipantAdded;
data.Conversation.StateChanged += Conversation_ConversationChangedEvent;
// Add a remote participant.
data.Conversation. AddParticipant(_LyncClient.ContactManager.GetContactByUri(this.myRemoteParticipantUri));
}
ParticipantAdded Event
The following example handles the ParticipantAdded event. The example event handler gets the instant messaging modality from the modality collection on the new participant and registers for messages received from the participant. InstantMessageReceived is raised on any participant when that participant sends a message.
/// <summary>
/// ParticipantAdded callback handles ParticpantAdded event raised by Conversation
/// </summary>
/// <param name="source">Conversation Source conversation.</param>
/// <param name="data">ParticpantCollectionEventArgs Event data</param>
void Conversation_ParticipantAdded(Object source, ParticipantCollectionChangedEventArgs data)
{
if (data.Participant.IsSelf == false)
{
if (((Conversation)source).Modalities.ContainsKey(ModalityTypes.InstantMessage))
{
((InstantMessageModality)data.Participant.Modalities[ModalityTypes.InstantMessage]).InstantMessageReceived += myInstantMessageModality_MessageReceived;
((InstantMessageModality)data.Participant.Modalities[ModalityTypes.InstantMessage]).IsTypingChanged += myInstantMessageModality_ComposingChanged;
}
}
}
User starts typing
A user’s cursor has entered a text entry control and the example sets the IsTyping property to true.
Important
The conversation instant message modality must be used to set the typing property for the local user rather than the instant message modality of the local participant.
private void txtMessage_Enter(object sender, EventArgs e)
{
if ((InstantMessageModality)_Conversation.Modalities[ModalityTypes.InstantMessage]).CanInvoke(ModalityAction.SetIsTyping))
{
((InstantMessageModality)_Conversation.Modalities[ModalityTypes.InstantMessage]).BeginSetComposing(true, ComposingCallback, null);
}
}
User completes typing.
A user’s cursor has left a text entry control and the example sets the IsTyping property to false.
Important
The conversation instant message modality must be used to set the typing property for the local user rather than the instant message modality of the local participant.
private void txtMessage_Leave(object sender, EventArgs e)
{
if ((InstantMessageModality)_Conversation.Modalities[ModalityTypes.InstantMessage]).CanInvoke(ModalityAction.SetIsTyping))
{
((InstantMessageModality)_Conversation.Modalities[ModalityTypes.InstantMessage]).BeginSetComposing(false, ComposingCallback, null);
}
}
Send a Message in Plain Text
The following example sends the text content of a user interface text box to a remote conversation participant.
Important
The conversation instant message modality must be used to send an instant message to other users instead of the local participant’s instant message modality.
private void SendMessage(string messageToSend)
{
try
{
IDictionary<InstantMessageContentType, string> textMessage = new Dictionary<InstantMessageContentType, string>();
textMessage.Add(InstantMessageContentType.PlainText, messageToSend);
if (((InstantMessageModality)_Conversation.Modalities[ModalityTypes.InstantMessage]).CanInvoke(ModalityAction.SendInstantMessage))
{
((InstantMessageModality)_Conversation.Modalities[ModalityTypes.InstantMessage]).BeginSendMessage(
textMessage
, SendMessageCallback
, textMessage);
}
}
catch (LyncPlatformException e)
{
MessageBox.Show("Client Platform Exception: " + e.Message, "Send Message");
}
}
SendMessage Callback
The following example callback method is invoked by InstantMessageModality after BeginSendMessage is complete. Verify asynchronous operation results here if you want to see if the message was sent successfully.
/// <summary>
/// Async callback method invoked by InstantMessageModality instance when SendMessage completes
/// </summary>
/// <param name="_asyncOperation">IAsyncResult The operation result</param>
///
private void SendMessageCallback( IAsyncResult ar)
{
((InstantMessageModality)_Conversation.Modalities[ModalityTypes.InstantMessage]).BeginSetComposing(false, ComposingCallback, null);
if (ar.IsCompleted == true)
{
try
{
((InstantMessageModality)_Conversation.Modalities[ModalityTypes.InstantMessage]).EndSendMessage(ar);
}
catch (LyncClientException lce)
{
MessageBox.Show("Lync Client Exception on EndSendMessage " + lce.Message);
}
}
}
ComposingChanged Event
The following example handles the event raised when a participant starts or stops typing.
void myInstantMessageModality_ComposingChanged(object source, IsTypingChangedEventArgs data)
{
if (data.IsTyping == true
{
MessageBox.Show(((InstantMessageModality)source).Participant.Contact.GetContactInformation(ContactInformationType.DisplayName) + " is typing");
}
}
InstantMessageModality MessageReceived Event
The following example handles the InstantMessageReceived. This example uses the PlainText enumerator. If this enumerator is used, message content is rendered as plain text regardless of how it was formatted by the sender. If the incoming message contains data that cannot be rendered as plain text, the data is not rendered.
/// <summary>
/// Callback is invoked when IM Modality state changes upon receipt of message
/// </summary>
/// <param name="source">InstantMessageModality Modality </param>
/// <param name="data">SendMessageEventArgs The new message.</param>
void myInstantMessageModality_MessageReceived(Object source, MessageSentEventArgs data)
{
IDictionary<InstantMessageContentType,string> messageFormatProperty = data.Contents;
if (messageFormatProperty.ContainsKey(InstantMessageContentType.PlainText))
{
string outVal = string.Empty;
string Sender = (string)((InstantMessageModality)source).Participant.Contact.GetContactInformation(ContactInformationType.DisplayName);
if (messageFormatProperty.TryGetValue(InstantMessageContentType.PlainText, out outVal))
{
//outVal will be an empty string if the received message contains only an image.
MessageBox.Show("New message: " + outVal);
//invoke delegate that sets text property of a form browser control with outVal
}
}
}