How to: Start resource sharing conversations

[This is preliminary documentation and is subject to change.]

Describes how to start a sharing conversation and get a list of shareable resources that are shared in the conversation. For an overview of resource sharing in Microsoft Lync 2013 Preview, see Resource Sharing in Lync.

This topic describes how to build the UI elements highlighted in figure 1 by completing the following tasks. For more information about the Share Resources sample application, see How Do I in Resource Sharing.

  • Getting a list of the contact SIP addresses for the contacts in the user’s contact list.

  • Starting a conversation.

  • Getting a list of all shareable local resources.

  • Registering for events on all application sharing modalities.

  • Starting to share a resource.

This topic discusses how to start a conversation in the context of resource sharing. For more information about starting a conversation, see How to: Start an IM Conversation.

Figure 1. The Share Resources application Windows Form controls that are discussed in this topic

Conversation starting-related controls highlighted
Important note Important

You can only get shareable resources in the context of an active conversation. For this reason, the following examples do not fill the shared resources list until after the conversation is started. For more information about how to create a contact list, see How to: Fill a Contact List.

Before you complete the steps in this topic, your application must declare and initialize an instance of Microsoft.Lync.Model.LyncClient. The Lync client must be signed in. For more information to, see How to: Sign In to Lync.

In addition to the Microsoft.Lync.Model.LyncClient instance, your application must declare a button and two lists. The first list displays contact Sip addresses for Lync users, the button starts the conversation, and the second list displays the resources that can be shared in the new conversation. The Sip address list should let a user select multiple addresses so that multiple users can be invited to join the new conversation.

To make the following example code easier to read, several conversation-related API state objects are stored in class fields. These objects include the following:

Code example

The following example references the namespaces that are used in the following Windows Forms examples.

using System;
using System.Windows.Forms;
using Microsoft.Lync.Model;
using Microsoft.Lync.Model.Group;
using Microsoft.Lync.Model.Conversation;
using Microsoft.Lync.Model.Conversation.Sharing;
using System.Collections.Generic;

The following example declares the class fields that are referenced in the following sections of this topic.

        /// <summary>
        /// Lync client platform. The entry point to the API
        /// </summary>
        Microsoft.Lync.Model.LyncClient _LyncClient;
 
        /// <summary>
        /// Represents a Lync conversation
        /// </summary>
        Conversation _conversation;

        /// <summary>
        /// A Contact instance representing the participant selected to be granted control of a resource
        /// </summary>
        Contact _ResourceControllingContact;
 
        /// <summary>
        /// Dictionary of all contacts selected from the multi-select enabled contact list on UI
        /// </summary>
        Dictionary<string, Contact> _selectedContacts = new Dictionary<string, Contact>();
 
        /// <summary>
        /// Collection of all participants application sharing modalities, keyed by Contact.Uri.
        /// </summary>
        Dictionary<string, ApplicationSharingModality> _participantSharingModalities = new Dictionary<string, ApplicationSharingModality>();
 
        /// <summary>
        /// The Application sharing modality of the conversation itself
        /// </summary>
        ApplicationSharingModality _sharingModality;
 
        /// <summary>
        /// The Application sharing modality of the local participant.
        /// </summary>
        ApplicationSharingModality _LocalParticipantSharingModality;

The sample is ready to start a new conversation or host a conversation that the signed in user is invited to as soon as the logic in the form load event finishes.

The Microsoft.Lync.Model.Conversation.ConversationManager class lets you start a new conversation. Get a ConversationManager instance and register for events on it before you can start any of the other tasks in this topic.

To handle the form loaded event

  1. Get the API entry point by calling the static LyncClient.GetClient method. Put the returned Microsoft.Lync.Model.LyncClient object into the _lyncClient class field declared previously.

  2. Read the LyncClient.InSuppressedMode property of the client. If false is returned, continue with the next step. Otherwise, stop this procedure. Resource sharing is not supported when UI suppression is enabled.

  3. Read the Client.State property and continue to the next step if the current state is ClientStateSignedin(). Otherwise, sign in to Lync with the user’s credentials.

  4. Read the Client.ConversationManager property of the Microsoft.Lync.Model.LyncClient.

  5. Register a callback method for the ConversationManager.ConversationAdded and ConversationManager.ConversationRemoved events on the conversation manager.

  6. Get the Sip addresses of all contacts in the user’s contact list.

Important note Important

The example code in the How Do I in Resource Sharing section is driven by the chain of events started when the ConversationManager.AddConversation method is called. The event callback method that is invoked for ConversationManager.ConversationAdded adds the invited users to the new Microsoft.Lync.Model.Conversation.Conversation object. For each user who is added to the conversation, a Conversation.ParticipantAdded event is raised. The event callback method that is invoked for this event gets the new participant’s Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingModality, and then registers event handlers for events on the participant’s sharing modality. The sharing modality events drive the UI state changes that enable or prevent a user from performing actions on the shared resource.

Code example

The following example gets the Microsoft.Lync.Model.LyncClient and registers for events on the LyncClient and the ConversationManager instance.

Note Note

The code in this example assumes that a user has signed in to Lync 2013 Preview. For information about how to sign a user into the client programmatically, see How to: Sign In to Lync.

        /// <summary>
        /// invoked when sample form is loaded. Initializes fields, gets API entry point, 
        /// registers for events on Lync Client and ConversationManager.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ShareResources_Form_Load(object sender, EventArgs e)
        {
            try
            {
                //Get the API entry point
                _LyncClient = LyncClient.GetClient();
 
 
                //Resource sharing is not supported in UI suppression mode. Sample closes
                //if Lync UI is suppressed
                if (_LyncClient.InSuppressedMode == true)
                {
                    MessageBox.Show("Lync Client is in UI Suppressed mode. Sharing is not supported.""Application Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                    this.Close();
                }
 
                //If the Lync client is signed out, sign into the Lync client
                if (_LyncClient.State == ClientState.SignedOut)
                {
                    _LyncClient.EndSignIn(_LyncClient.BeginSignIn(
                        "AndreasH@contoso.com",
                        "AndreasH@contoso.com",
                        "My_Passw0rd",
                        null,
                        null));
                }
 
                //Register for the three Lync client events needed so that application is notified when:
                // * Lync client signs in or out
                // * A new conversation is added (remotely via invite or locally by user)
                // * A conversation is removed (conversation ends)
                _LyncClient.StateChanged += _LyncClient_StateChanged;
                _LyncClient.ConversationManager.ConversationAdded += ConversationManager_ConversationAdded;
                _LyncClient.ConversationManager.ConversationRemoved += ConversationManager_ConversationRemoved;
 
                //Get the Sip addresses of all contacts in the user’s contact list.                
                //ShareResources.LoadAllContacts loads the contact list on the UI with
                //all contacts that are in the user's Lync client contact list.
                LoadAllContacts(); 
            }
            catch (ClientNotFoundException)
            {
                MessageBox.Show("Client is not running.  Closing form""Lync Client Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                this.Close();
            }
            catch (Exception exc)
            {
                MessageBox.Show("General exception: " + exc.Message, "Lync Client Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                this.Close();
            }
 
        }


The form is now loaded and the user’s contact list is displayed in the contact list in the UI.

To get the contacts that a user has added to the local contact list, you must read the Client.ContactManager property and then get the collection of Microsoft.Lync.Model.Group.Group objects by reading the ContactManager.Groups property. For more information about retrieving contacts, see How to: Fill a Contact List.

To get the user’s contacts

  1. Read the Client.ContactManager property on the _LyncClient class field.

  2. Read the ContactManager.Groups property on the contact manager. A collection of Microsoft.Lync.Model.Group.Group objects is returned.

  3. Iterate on the Group objects.

    Tip Tip

    A Group is a collection of contacts that can be treated as a Microsoft.Lync.Model.Contact object collection.

  4. For each Group, iterate over the Contact objects.

  5. For each contact, add the user’s Sip address to the contact list on the UI. Get the Sip address by reading the Contact.Uri property.

Code example

The following example updates the UI of the application by using the current state of the client, gets the user’s URI, checks the state of the room manager and adds the title of every room in the followed room collection to a list in the persistent chat room UI.

        /// <summary>
        /// Iterates on all groups and adds an Uri string for each contact in a group to a list on the UI
        /// </summary>
        private void LoadAllContacts()
        {
            //Set the selection mode of the UI list to multi-select
            Contact_ListBox.SelectionMode = SelectionMode.MultiSimple;
            Contact_ListBox.Items.Clear();
            foreach (Group group in _LyncClient.ContactManager.Groups)
            {
                foreach (Contact contact in group)
                {
                    if (!Contact_ListBox.Items.Contains(contact.Uri))
                       Contact_ListBox.Items.Add(contact.Uri);
                }
            }
        }

Tip Tip

A contact can be in multiple groups. To avoid adding the same contact to the list two times, the previous example checks whether the contact has already been added to the list when it is processing successive groups.

A user may select as many contacts as they want to invite to a conversation. The list declared in the sample form is enabled for multiple selections. Each selection is only a Sip address and corresponding Microsoft.Lync.Model.Contact objects are needed when you are adding selected contacts to the new conversation.

For each Sip address selected on the contact list, the sample gets the corresponding Contact by calling the ContactManager.GetContactByUri method. The contact objects are stored in the _selectedContacts dictionary that was declared previously and then used in the ConversationManager.ConversationAdded event.

Important note Important

When you add a new conversation, you have only started a Sip dialog with Microsoft Lync Server 2013 Preview but you have not set a list of users to be invited or registered for conversation-related events yet. You must wait for a confirmation from Lync Server 2013 Preview that a conversation Sip dialog is established. You are notified in the ConversationAdded event.

Code example

The following example starts a new conversation.

        /// <summary>
        /// Starts a new conversation
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Start_Button_Click(object sender, EventArgs e)
        {
            Contact aContact;
            foreach (Object selectedObject in Contact_ListBox.SelectedItems)
            {
                aContact = _LyncClient.ContactManager.GetContactByUri(selectedObject.ToString());
                if (!_selectedContacts.ContainsKey(selectedObject.ToString()))
                {
                    _selectedContacts.Add(selectedObject.ToString(), aContact);
                }
            }
            _conversation = _LyncClient.ConversationManager.AddConversation();
        }

The ConversationManager.ConversationAdded event is raised when the conversation is established and you can add users to the conversation and register event callback methods for the conversation-related events.

Register for events on the conversation, and the Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingModality of the new conversation. This includes the participant that represents the local user. The best place to register for the conversation ApplicationSharingModality events is in the ConversationAdded event callback method. You must register for all participant’s ApplicationSharingModality events in your Conversation.ParticipantAdded event.

Handling the ConversationAdded event

Although the ConversationManager.AddConversation method returns a new Microsoft.Lync.Model.Conversation.Conversation object synchronously, a set of Sip messages is sent to Lync Server 2013 Preview and used by the server to create a client/server Sip dialog that will encapsulate the conversation. When the Sip dialog is established, the ConversationManager.ConversationAdded event is raised. Use this event to register for conversation-related events and send conversation invitations to all of the contacts that the user selected. The following procedure describes the tasks completed by the event callback method that handles ConversationAdded.

Tip Tip

This sample class listens for any new conversation either started by the local user or by another user who invites the local user. When this kind of conversation is added, it only hosts that conversation and is not designed to handle additional new conversations. To make this possible, the sample un-registers the ConversationAdded event callback. The callback is re-registered when the conversation is ended.

To handle the ConversationAdded event

  1. Un-register the event callback method on ConversationManager.ConversationAdded so that the sample ignores any other new conversations until this conversation is finished.

  2. Register for the Conversation.StateChanged and Conversation.ParticipantAdded events on the new conversation.

  3. Store the Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingModality object from the Conversation.

  4. Register event callback methods for all of the events that are exposed by the conversation ApplicationSharingModality.

  5. Add participants to the new conversation.

After the ConversationAdded event callback method is finished, the application is listening for events on the conversation ApplicationSharingModality, and invitations have been sent to the contacts that are added to the conversation.

Code example

The following example handles the ConversationAdded event.

        /// <summary>
        /// Handles the event raised when a new conversation is added. This sample only hosts one conversation
        /// at a time. Once this event is handled, the sample un-registers for this event. The event is registered again when
        /// this conversation is removed from the ContactManager.Conversations collection upon termination of this conversation.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ConversationManager_ConversationAdded(object sender, Microsoft.Lync.Model.Conversation.ConversationManagerEventArgs e)
        {
            //Flag that indicates that the new conversation was started locally instead of by a remote user. 
            Boolean addedByThisProcess = true;
 

            //Suspend hosting new conversations until this conversation is ended
            _LyncClient.ConversationManager.ConversationAdded -= ConversationManager_ConversationAdded;

            //If this class field is null then the new conversation was not started by this running process. It was
            //Started by the Lync client or by a remote user.
            if (_conversation == null)
            {
                addedByThisProcess = false;
                _conversation = e.Conversation;
            }

            //Register for conversation state changes such as Active->Terminated.
            _conversation.StateChanged += _conversation_StateChanged;
 
            //Register for participant added events on the new conversation
            //The next important action in the chain of conversation intiating action happens in the ParticipantAdded event handler.
            _conversation.ParticipantAdded += _conversation_ParticipantAdded;
            _conversation.ParticipantRemoved += _conversation_ParticipantRemoved;
 
            //Register for the application sharing modality event on the conversation itself
            _sharingModality = (ApplicationSharingModality)_conversation.Modalities[ModalityTypes.ApplicationSharing];
 
            //Register for state changes like connecting->connected
            _sharingModality.ModalityStateChanged += _sharingModality_ModalityStateChanged;
 
            //Register to catch requests from other participants for control of the locally owned sharing resource.
            _sharingModality.ControlRequestReceived += _sharingModality_ControlRequestReceived;
            _sharingModality.ControllerChanged += _sharingModality_ControllerChanged;
 
            //Register to catch changes in the list of local sharable resources such as a process that starts up or terminates.
            _sharingModality.LocalSharedResourcesChanged += _sharingModality_LocalSharedResourcesChanged;
 
            //Register for changes in the availbility of resource controlling actions such as grant and revoke.
            _sharingModality.ActionAvailabilityChanged += _sharingModality_ActionAvailabilityChanged;
 
            //Register for changes in the local participant's mode of sharing participation
            // such as Viewing->Sharing, Requesting Control->Controlling.
            _sharingModality.ParticipationStateChanged += _sharingModality_ParticipationStateChanged;
 

            // If the new conversation was started by the local user, the conversation does not have
            // any participants yet. Participants are added from the contacts selected by the local user
            if (addedByThisProcess == true)
            {
                Contact aContact;
 
                //Clear out the contact list on the UI to be replaced with only the contacts selected for the current conversation.
                this.Invoke(new ClearAllContactsDelegate(ClearAllContacts));
 
                //Iterate on the contact dictionary that is filled from the contact Sip addresses selected from the 
                //contact list UI control. Add each selected contact to the conversation, causing an invitation to be
                //sent to each contact.
                foreach (Contact selectedContact in _selectedContacts.Values)
                {
                    Participant newParticipant =  _conversation.AddParticipant(selectedContact);
                    this.Invoke(new AddAContactDelegate(AddAContact), new object[] { selectedContact.Uri });
                }
            }
 
            //Update the list of local sharable resources on the UI
            this.Invoke(new UpdateSharedResourcesListboxDelegate(UpdateSharedResourcesListbox));
 
            //Set the enabled state of the resource sharing button, end conversation button, and start conversation button.
            this.Invoke(new EnableDisableButtonDelegate(EnableDisableButton), new object[] { StartSharingResource_Button, true });
            this.Invoke(new EnableDisableButtonDelegate(EnableDisableButton), new object[] { EndConversation_Button, true });
            this.Invoke(new EnableDisableButtonDelegate(EnableDisableButton), new object[] { Start_Button, false });
 
        }

Handling the ParticipantAdded event

The Conversation.ParticipantAdded event is raised when a participant is added to the Conversation object. A ParticipantAdded event callback must handle the following tasks:

The following example registers for the Conversation.ParticipantAdded event and also stores the participant Microsoft.Lync.Model.Conversation.Sharing.ApplicationSharingModality object in a dictionary that uses the Contact.Uri string as a key. To grant control of a locally shared resource in the conversation, the appropriate participant ApplicationSharingModality will be retrieved from the dictionary by the user’s URI and then the ApplicationSharingModality.BeginGrantControl method is called on modality.

Code example

The following example handles the Conversation.ParticipantAdded event.

        /// <summary>
        /// Handles the participant added event. Registers for events on the application sharing modality for the 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _conversation_ParticipantAdded(object sender, ParticipantCollectionChangedEventArgs e)
        {
            //Is this added participant the local user?
            if (e.Participant.IsSelf)
            {
                //Store the application sharing modality of the local user so that
                //the user can request or release control of a remotely owned and shared resource.
                _LocalParticipantSharingModality = (ApplicationSharingModality)e.Participant.Modalities[ModalityTypes.ApplicationSharing];
 
                //Enable or disable the Start Resource Sharing button according to the role of the local participant.
                //Roles can be Presenter or Attendee.
                this.Invoke(new EnableDisableButtonDelegate(EnableDisableButton), new object[] { StartSharingResource_Button, (Boolean)e.Participant.Properties[ParticipantProperty.IsPresenter] });
 
                //Register for the particpant property changed event to be notified when the role of the local user changes.
                e.Participant.PropertyChanged += Participant_PropertyChanged;
            }
 
 
            //Get the application sharing modality of the added participant and store it in a class dictionary field for easy access later.
            ApplicationSharingModality participantSharingModality = (ApplicationSharingModality)e.Participant.Modalities[ModalityTypes.ApplicationSharing];
            _participantSharingModalities.Add(e.Participant.Contact.Uri, participantSharingModality);
 
            //register for important events on the application sharing modality of the new participant.
            participantSharingModality.ActionAvailabilityChanged += _sharingModality_ActionAvailabilityChanged;
            participantSharingModality.ModalityStateChanged += _sharingModality_ModalityStateChanged;
 
        }

Handling the ParticipantRemoved event

The Conversation.ParticipantRemoved event is raised when a participant has declined an invitation to join a conversation. Use this event to remove the ApplicationSharingModality object from the Dictionary that you added it to in the previous example. You should also un-register any event callback methods that you registered on this participant’s modalities when the participant was added.

Code example

The following example unregisters for participant events, removes the participant’s ApplicationSharingModality from the Dictionary, and then removes the URI of the participant from the UI list.

        /// <summary>
        /// Handles the event raised when a particpant is removed from the conversation.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void _conversation_ParticipantRemoved(object sender, ParticipantCollectionChangedEventArgs e)
        {
 
            //get the application sharing modality of the removed participant out of the class modalty dicitonary
            ApplicationSharingModality removedModality = _participantSharingModalities[e.Participant.Contact.Uri];
 
            //Un-register for modality events on this participant's application sharing modality.
            removedModality.ActionAvailabilityChanged -= _sharingModality_ActionAvailabilityChanged;
 
            //Remove the modality from the dictionary.
            _participantSharingModalities.Remove(e.Participant.Contact.Uri);

            //Remove the modality from the UI list.
            this.Invoke(new RemoveAContactDelegate(RemoveAContact), new object[] { e.Participant.Contact.Uri});
        }

Handling the ParticipantPropertyChanged event

If the self-participant IsPresenter property value changes from true to false, the local user has been demoted to attendee and can no longer share a local resource. If the property value changes from false to true, the local user has been promoted to presenter and can share local resources in the conversation. Use this event to update your UI controls that start sharing a resource.

Code example

The following example enables or disables a UI button that starts resource sharing.

        /// <summary>
        /// Called when a participant property is changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void Participant_PropertyChanged(object sender, ParticipantPropertyChangedEventArgs e)
        {
            if (e.Property == ParticipantProperty.IsPresenter)
            {
                //Enable or disable the Start Sharing Resource button according to the participant role
                this.Invoke(new EnableDisableButtonDelegate(EnableDisableButton), new object[] { StartSharingResource_Button, (Boolean)e.Value });
            }
        }

You can fill or refresh a UI list of locally shareable resources at any time after the conversation is created. The best place to call a method that does this is in the ConversationManager.ConversationAdded event.

Important note Important

You must get the locally shareable resources from the ConversationMicrosoft.Lync.Model.Conversation.Sharing.ApplicationSharingModality instead of any participant ApplicationSharingModality.

Code example

The following example fills a list that has the resources that can be shared in a conversation.

        /// <summary>
        /// Fills a UI list with the names of all local resources that can be shared.
        /// </summary>
        private void UpdateSharedResourcesListbox()
        {
            SharedResources_ListBox.Items.Clear();
            if (_sharingModality == null || _sharingModality.ShareableResources == null)
            {
                return;
            }
            if (_sharingModality.ShareableResources.Count > 0)
            {
                SharingResource sharingResource;
                for (int j = 0; j < _sharingModality.ShareableResources.Count; j++)
                {
                    sharingResource = _sharingModality.ShareableResources[j];
                    SharedResources_ListBox.Items.Add(sharingResource.Name);
                }
            }
        }

The event callback methods in this topic call the following helper methods by invoking delegates on the UI thread. These methods update a contact list and buttons that appear in the UI.

        private delegate void ClearAllContactsDelegate();
        /// <summary>
        /// Clears the UI contact list of all items.
        /// </summary>
        private void ClearAllContacts()
        {
            Contact_ListBox.Items.Clear();
        }
 
        private delegate void AddAContactDelegate(string ContactUri);
        /// <summary>
        /// Adds the Uri of a contact to the UI contact list.
        /// </summary>
        private void AddAContact(string ContactUri)
        {
            Contact_ListBox.SelectionMode = SelectionMode.One;
            if (!Contact_ListBox.Items.Contains(ContactUri))
            {
                Contact_ListBox.Items.Add(ContactUri);
            }
        }

        private delegate void RemoveAContactDelegate(string ContactUri);
        /// <summary>
        /// Removes the Uri of a contact from the UI contact list.
        /// </summary>
        private void RemoveAContact(string ContactUri)
        {
            Contact_ListBox.Items.Remove(ContactUri);
        }

        private delegate void EnableDisableButtonDelegate(Button buttonToUpdate, Boolean actionAvailability);
        /// <summary>
        /// Enables or disables a UI button.
        /// </summary>
        private void EnableDisableButton(Button buttonToUpdate, Boolean actionAvailability)
        {
            buttonToUpdate.Enabled = actionAvailability;
        }



When your application has completed the tasks in this topic, a resource sharing conversation is active with one or more participants in addition to the local user. The application UI shows a list of the conversation’s participants and a list of the local resources that can be shared in the conversation.

For information about sharing one of these resources, see How to: Get shareable resources and share them in a conversation. For information about how to manage the control of the shared resource, see How to: Grant and revoke control of shared resources. For information about requesting and releasing control of a resource shared by another user in a conversation, see How to: Request and release control of shared resources.

Community Additions

Show:
© 2014 Microsoft