Walkthrough: Dock a Conversation Window in a WPF Page (Lync 2010 SDK)

This topic shows how to configure your application to accept an incoming conversation and then start a conversation.

Conversation window docking in a Microsoft Windows Presentation Foundation (WPF) form requires the same programming steps that are used to dock a conversation window in a Windows form. In addition, steps show how to embed a WindowsFormsHost control in your XAML document. This host control becomes the parent of the conversation window that is docked.

Important

If you create a Microsoft Silverlight application, you must make all Microsoft Lync 2010 API calls on your UI thread. Lync 2010 API events are raised on the API thread. To update your UI controls from event handlers for these events, you use Dispatcher.Invoke to call methods on your UI thread and pass relevant event data to those UI thread methods.

Prerequisites

For a list of prerequisites, see Walkthrough: Start an Instant Message Conversation (Lync 2010 SDK).

Creating the Conversation Window Docking WPF Application

The walkthrough example uses an instance of Microsoft.Lync.Model.Conversation.ConversationManager to accept an incoming conversation and registers for the ConversationManager.ConversationAdded event.

To create a conversation window docking application by using WPF, you add a WindowsFormsHost element to your XAML document. For information about hosting a Windows Forms Control in your WPF application, see Walkthrough: Hosting a Windows Forms Control in WPF by Using XAML.

The ConversationManager.ConversationAdded event is raised by the Lync thread instead of the main UI thread. The example declares a delegate and marshals the event data to the UI thread by invoking the delegate on the UI thread. The delegated method docks the conversation window within the WindowsFormsHost instance.

To create the IM conversation window docking Windows Forms Host Control

  1. Sign in to Microsoft Lync 2010.

  2. Add a reference to Microsoft.Lync.Model in your project reference folder. Browse to %ProgramFiles%\Microsoft Lync\SDK\Assemblies\WPF\ folder and choose Microsoft.Lync.Model.dll.

  3. Create a new class that calls the Lync 2010 API and handles events raised by the Lync 2010 API.

    using System;
    using System.Collections.Generic;
    using System.Text;
    using Microsoft.Lync.Model;
    using Microsoft.Lync.Model.Conversation;
    using Microsoft.Lync.Model.Extensibility;
    
    namespace WPFDockingExample
    {
        public delegate void  NewConversationDelegate(string NewConversationId);
        public delegate void ConversationRemovedDelegate();
        public delegate void ConversationWindowNeedsAttentionDelegate();
        public delegate void ConversationWindowNeedsSizeChangeDelegate(int newHeight, int newWidth);
    
        class AppLyncModel
        {
            public event NewConversationDelegate NewConversationEvent;
            public event ConversationWindowNeedsAttentionDelegate ConversationWindowNeedsAttentionEvent;
            public event ConversationWindowNeedsSizeChangeDelegate ConversationWindowNeedsSizeChangedEvent;
            public event ConversationRemovedDelegate ConversationRemoveEvent;
    
    
            LyncClient myLyncClient;
            Automation myAutomation;
            Dictionary<string, Conversation> myNewConversation;
    
    
            /// <summary>
            /// Docks a ConversationWindow in a Windows Forms control that is associated with passed handle
            /// </summary>
            /// <param name="ConversationId">string. Id of conversation to be docked.</param>
            /// <param name="PanelHandle">int. Handle of Windows Form Control to dock the conversation within.</param>
            public void WindowPanelHandle(string ConversationId, int PanelHandle)
            {
                Conversation conversationToDock;
                if (myNewConversation.TryGetValue(ConversationId, out conversationToDock))
                {
                    ConversationWindow cw = myAutomation.GetConversationWindow(conversationToDock);
                    cw.NeedsAttention += cw_NeedsAttention;
                    cw.NeedsSizeChange += cw_NeedsSizeChange;
                    cw.Dock(PanelHandle);
                }
            }
    
            /// <summary>
            /// Raised when the ConversationWindow instance requires the parent control to change its size
            /// </summary>
            /// <param name="sender">object. The ConversationWindow instance raising the event.</param>
            /// <param name="e">ConversationWindowNeedsSizeChangeEventArgs. The event state data.</param>
            void cw_NeedsSizeChange(object sender, ConversationWindowNeedsSizeChangeEventArgs e)
            {
                if (ConversationWindowNeedsSizeChangedEvent != null)
                {
                    ConversationWindowNeedsSizeChangedEvent(((Conversation)sender).Properties[ConversationProperty.Id].ToString(), e.RecommendedWindowHeight, e.RecommendedWindowWidth);
                }
            }
    
            /// <summary>
            /// Raised when the parent of the docked ConversationWindow should get focus
            /// </summary>
            /// <param name="sender">object. The ConversationWindow instance raising the event.</param>
            /// <param name="e">ConversationWindowNeedsAttentionEventArgs. The event state data.</param>
            void cw_NeedsAttention(object sender, ConversationWindowNeedsAttentionEventArgs e)
            {
                if (ConversationWindowNeedsAttentionEvent != null)
                {
                    ConversationWindowNeedsAttentionEvent(((Conversation)sender).Properties[ConversationProperty.Id].ToString());
                }
            }
    
            /// <summary>
            /// Raised when a conversation ends
            /// </summary>
            /// <param name="sender">object. The ConversationManager.</param>
            /// <param name="e">ConversationManagerEventArgs. The Event state data.</param>
            void ConversationManager_ConversationRemoved(object sender, ConversationManagerEventArgs e)
            {
                if (ConversationRemoveEvent != null)
                {
                    ConversationRemoveEvent(((Conversation)sender).Properties[ConversationProperty.Id].ToString());
                }
            }
    
            /// <summary>
            /// Raised when a new conversation is added to the Conversations collection of the ConversationManager instance
            /// </summary>
            /// <param name="sender">object. The ConversationManager.</param>
            /// <param name="e">ConversationManagerEventArgs. The Event state data.</param>
            void ConversationManager_ConversationAdded(object sender, ConversationManagerEventArgs e)
            {
                if (NewConversationEvent != null)
                {
                    myNewConversation.Add(e.Conversation.Properties[ConversationProperty.Id].ToString(), e.Conversation);
                    NewConversationEvent(e.Conversation.Properties[ConversationProperty.Id].ToString());
                }
            }
    
            /// <summary>
            /// Class constructor
            /// </summary>
            public AppLyncModel()
            {
                myLyncClient = LyncClient.GetClient();
                if (myLyncClient.State != ClientState.SignedIn)
                {
                    throw new Exception("Lync is not signed in");
                }
                myNewConversation = new Dictionary<string, Conversation>();
    
                myAutomation = Microsoft.Lync.Model.LyncClient.GetAutomation();
                myLyncClient.ConversationManager.ConversationAdded += ConversationManager_ConversationAdded;
                  myLyncClient.ConversationManager.ConversationRemoved += ConversationManager_ConversationRemoved;
            }
        }
    }
    
  4. In your WPF application, open the MainWindow.XAML source and add the following attribute to the Window XAML element.

    xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
    
  5. Within the Windows Forms host, add a WindowsFormsHost and Panel element.

            <WindowsFormsHost>
                <wf:Panel Name="ConversationPanel" />
            </WindowsFormsHost>
    
  6. Add the following code to the MainWindow.xaml.cs file. Position the code inside the namespace declaration and before the class declaration. These delegate declarations are used to marshal event data to the main UI thread from within the Lync client thread.

        delegate void DockConversationDelegate(string ConversationId);
        delegate void ResizeConversationDelegate(int newHeight, int newWidth);
        delegate void FocusConversationPanelDelegate(string ConversationId);
        delegate void HideConversationPanelDelegate();
    
    
  7. Add the following code to the MainWindow.xaml.cs file to declare an instance of the AppLyncModel class that is created in step 3.

            AppLyncModel _LyncModel;
    
  8. Add the following code to the MainWindow constructor. This example code instantiates an instance of the AppLyncModel class that is created in step 3, and then registers for events that are related to the conversation window that is docked within the WPF page.

            _LyncModel = new AppLyncModel();
            _LyncModel.NewConversationEvent += _LyncModel_NewConversationEvent;
            _LyncModel.ConversationRemoveEvent += _LyncModel_ConversationRemoveEvent;
            _LyncModel.ConversationWindowNeedsAttentionEvent += _LyncModel_ConversationWindowNeedsAttentionEvent;
            _LyncModel.ConversationWindowNeedsSizeChangedEvent += _LyncModel_ConversationWindowNeedsSizeChangedEvent;
    
  9. Add the following methods to the MainWindow class. The events handled by these methods are raised by the AppLyncModel class that is created in step 3.

    
            /// <summary>
            /// Called by AppLyncModel when a new conversation is created
            /// </summary>
            /// <param name="NewConversationId">string. Id of new conversation.</param>
            void _LyncModel_NewConversationEvent(string NewConversationId)
            {
                ConversationPanel.Invoke(new DockConversationDelegate(DockTheConversation), new object[] { NewConversationId });
            }
    
            /// <summary>
            /// Called by AppLyncModel when the docked conversation window size changes
            /// </summary>
            /// <param name="newHeight">int. The new recommended height of the WPF page</param>
            /// <param name="newWidth">int. The new recommended width of the WPF page</param>
            void _LyncModel_ConversationWindowNeedsSizeChangedEvent(int newHeight, int newWidth)
            {
                this.Dispatcher.Invoke(new ResizeConversationDelegate(ResizePage), new object[] {newHeight+10, newWidth+10 });
            }
    
            /// <summary>
            /// Called by AppLyncModel when there is activity in the conversation window
            /// </summary>
            void _LyncModel_ConversationWindowNeedsAttentionEvent()
            {
                ConversationPanel.Invoke(new FocusConversationPanelDelegate(FocusThePage), new object[] { });
            }
    
            /// <summary>
            /// Called by AppLyncModel when the conversation ends
            /// </summary>
            void _LyncModel_ConversationRemoveEvent(string ConversationToRemoveId)
            {
                 ConversationPanel.Invoke(new HideConversationPanelDelegate(HideConversationPanel), new object[] { ConversationToRemoveId });
            }
    
            /// <summary>
            /// Invoked on the UI thread when a new conversation is added and needs to be docked
            /// </summary>
            /// <param name="ConversationId">string. Id of new conversation.</param>
            private void DockTheConversation(string ConversationId)
            {
                 _LyncModel.WindowPanelHandle(ConversationId, ConversationPanel.Handle.ToInt32());
            }
    
            /// <summary>
            /// Invoked on UI thread when a conversation ends
            /// </summary>
            private void HideConversationPanel(string ConversationId)
            {
                ConversationPanel.Hide();
                this.Height = 350;
                this.Width = 525;
            }
    
            /// <summary>
            /// Invoked on UI thread when the WPF page needs focus
            /// </summary>
            private void FocusThePage()
            {
                this.Focus();
            }
            /// <summary>
            /// Invoked on UI thread when WPF page needs size change
            /// </summary>
            /// <param name="newHeight">int. New recommended height of page.</param>
            /// <param name="newWidth">int. New recommended width of page.</param>
            private void ResizePage(int newHeight, int newWidth)
            {
                this.Height = newHeight;
                this.Width = newWidth;
            }
    
    
  10. Press F5 to build and run the application.

See Also

Concepts

Walkthrough: Dock a Conversation Window in a Windows Form (Lync 2010 SDK)

Other Resources

Lync Extensibility API Conversation Walkthroughs (Lync 2010 SDK)