/// <summary>
        /// Creates a new <see cref="ViewerPresentationLayout"/> instance and instantiates all of the child controls.
        /// </summary>
        /// <param name="model">The model whose <see cref="WorkspaceModel.CurrentDeckTraversal"/> property will
        /// be used to display the current slide and deck.</param>
        public ViewerPresentationLayout(PresenterModel model)
        {
            this.Name = "ViewerPresentationLayout";
            this.m_Model = model;

            this.m_EventQueue = new ControlEventQueue(this);

            m_Model.Workspace.CurrentDeckTraversal.ListenAndInitialize(m_EventQueue, new Property<DeckTraversalModel>.EventHandler(this.HandleTraversalChanged));

            // Create the film strip, docked to the right side of the container.
            this.m_DeckStrip = new DeckStrip(this.m_Model);
            /// Filmstrip docking
            this.m_DeckStrip.Dock = DockStyle.Right;

            // Make the deck strip resizable with a LinkedSplitter.
            // The splitter automatically sets its dock to be the same as the FilmStrip.
            this.m_DeckStripSplitter = new LinkedSplitter(this.m_DeckStrip);

            // Create the MainSlideViewer, which occupies the remaining space in the container.
            this.m_MainSlideViewer = new MainSlideViewer(this.m_Model, true);
            this.m_MainSlideViewer.Dock = DockStyle.Fill;

            #region RealTimeStylus Initialization
            // Create a new RealTimeStylus, which will process ink drawn on the MainSlideViewer.
            this.m_RealTimeStylus = new RealTimeStylus(this.m_MainSlideViewer, true);

            // Make sure the TransformableDynamicRenderer and InkAnnotationCollector
            // find out whenever the current StylusModel changes.
            this.m_StylusInputSelector = new StylusInputSelector(this.m_Model, this.m_RealTimeStylus);
            this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_StylusInputSelector);

            // Scale the ink to the inverse of the MainSlideViewer's transform.
            // This keeps the ink's coordinates correct when the MainSlideViewer's transform
            // is applied again later by the TransformableDynamicRenderer and InkAnnotationCollector.
            this.m_InkTransformFilter = new InkTransformFilter(this.m_MainSlideViewer.SlideDisplay);
            this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_InkTransformFilter);

            // Create a *synchronous* TransformableDynamicRenderer, which will render ink received directly
            // from the RealTimeStylus on a high-priority thread.
            this.m_TransformableDynamicRenderer = new TransformableDynamicRendererLinkedToDisplay(this.m_MainSlideViewer, this.m_MainSlideViewer.SlideDisplay);
            this.m_TransformableDynamicRenderer.Enabled = true;
            this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_TransformableDynamicRenderer);

            // Don't dynamically render ink on the main slide viewer twice.  The MainSlideViewer's RealTimeInkSheetRenderer's
            // own TransformableDynamicRenderer would render the ink on a low-priority asynchronous thread, which is
            // fine for secondary slide viewers and the FilmStrip, but not fine for the MainSlideViewer.
            using (Synchronizer.Lock(this.m_MainSlideViewer.SlideDisplay.SyncRoot)) {
                this.m_MainSlideViewer.SlideDisplay.RenderLocalRealTimeInk = false;
            }

            // Create an InkAnnotationCollector and wrap it in an InkSheetAdapter,
            // which sends ink from the RealTimeStylus to the RealTimeInkSheetModel
            // of the MainSlideViewer's current slide.
            this.m_InkAnnotationCollector = new InkAnnotationCollector();
            this.m_InkAnnotationCollector_InkSheetAdapter = new InkSheetAdapter(this.m_MainSlideViewer.SlideDisplay, this.m_InkAnnotationCollector);
            this.m_RealTimeStylus.AsyncPluginCollection.Add(this.m_InkAnnotationCollector);

            this.m_LassoPlugin = new LassoPlugin(this.m_MainSlideViewer, this.m_MainSlideViewer.SlideDisplay);
            this.m_LassoPlugin_InkSheetAdapter = new InkSheetAdapter(this.m_MainSlideViewer.SlideDisplay, this.m_LassoPlugin);
            this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_LassoPlugin);

            this.m_EraserPlugin = new EraserPlugin(this.m_MainSlideViewer.SlideDisplay);
            this.m_EraserPlugin_InkSheetAdapter = new InkSheetAdapter(this.m_MainSlideViewer.SlideDisplay, this.m_EraserPlugin);
            this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_EraserPlugin);

            // Now that all the plugins have been added, enable the RealTimeStylus.
            this.m_RealTimeStylus.Enabled = true;
            #endregion RealTimeStylus Initialization

            // Create a DeckTraversalModelAdapter, which causes the MainSlideViewer to always display the
            // current slide of the current deck of the PresenterModel's current DeckTraversalModel.
            this.m_WorkspaceModelAdapter = new WorkspaceModelAdapter(this.m_MainSlideViewer.SlideDisplay.EventQueue, this.m_MainSlideViewer, this.m_Model);

            // Create the Slide Preview control
            this.m_SlidePreview = new SlidePreview(this.m_Model, this.m_DeckStripSplitter);
            this.m_PreviewTraversalModelAdapter
                = new PreviewTraversalModelAdapter(this.m_SlidePreview.m_EventQueue, this.m_SlidePreview.m_PreviewSlideViewer, this.m_Model);

            // Create the Second Monitor Form, this displays the slide on the secondary display
            this.m_SecondMonitorForm = new SecondMonitorForm(this.m_Model);
            this.ParentChanged += new EventHandler(OnParentChanged);

            // Create the Role Synchronizer for the MainSlideViewer
            this.m_RoleSync = new RoleSynchronizer(this.m_MainSlideViewer, this.m_Model.Participant);

            #region Add Controls
            // Add the SlidePreview Control
            this.Controls.Add(this.m_SlidePreview);

            // Now, add the controls in reverse order of their docking priority.
            // The MainSlideViewer gets added first so its Fill dock-style will be effective.
            this.Controls.Add(this.m_MainSlideViewer);

            // Next, dock the FilmStripSplitter and the FilmStrip in reverse order,
            // so that the FilmStripSplitter will be farther away from the edge of the container.
            this.Controls.Add(this.m_DeckStripSplitter);
            this.Controls.Add(this.m_DeckStrip);

            #endregion Add Controls
        }
            protected override object SetUpMember(int index, object member)
            {
                TableOfContentsModel.Entry entry = ((TableOfContentsModel.Entry)member);
                FilmStripSlideViewer viewer;

                using (Synchronizer.Lock(entry.SyncRoot)) {
                    // Only deal with entries that are direct children of the TableOfContentsModel.
                    // Deeper entries are dealt with by the FilmStripSlideViewers.
                    if (entry.Parent != null)
                        return null;
                }

                Debug.Assert(this.m_Owner.IsHandleCreated);
                Debug.Assert(!this.m_Owner.InvokeRequired);

                this.m_Owner.SuspendLayout();
                viewer = new FilmStripSlideViewer(
                    this.m_Owner, this.m_Owner.m_Model, this.m_Owner.m_DeckTraversal,
                    this.m_Owner.m_PreviewDeckTraversal, entry);

                viewer.MyMouseDown += new MouseEventHandler(this.m_Owner.HandleMouseDown);
                viewer.MouseUp += new MouseEventHandler(this.m_Owner.HandleMouseUp);
                viewer.MouseEnter += new EventHandler(this.m_Owner.HandleSlideEnter);
                viewer.MouseLeave += new EventHandler(this.m_Owner.HandleSlideLeave);
                viewer.MouseMove += new MouseEventHandler(this.m_Owner.HandleSlideMove);
                try {

                    // Set the entry's Z-order.  The control at index 0 will be docked farthest
                    // away from the edge, so the "last" entry should be at index 0.
                    // Unfortunately we don't have a guarantee that all of the TableOfContentsModel's
                    // entries have yet been added to the FilmStrip (though that should be the case),
                    // so we just go through (starting with z-order 0, the last thing in the filmstrip)
                    // until we find the first entry whose index is less than ours.

                #if DEBUG
                    Debug.Assert(index >= 0);
                    using (Synchronizer.Lock(entry.TableOfContents.SyncRoot)) {
                        Debug.Assert(entry.TableOfContents.Entries.Count > index);
                    }
                #endif

                    int zOrder = 0;
                    using (Synchronizer.Lock(entry.SyncRoot)) {
                        int i;
                        for (i = 0; i < this.m_Owner.Controls.Count; i++) {
                            TableOfContentsModel.Entry en = ((FilmStripSlideViewer)(this.m_Owner.Controls[i])).m_Entry;
                            if (entry.TableOfContents.Entries.IndexOf(en) < entry.TableOfContents.Entries.IndexOf(entry)) {
                                zOrder = Math.Max(0, i);
                                i = this.m_Owner.Controls.Count + 1;
                            }
                        }
                        if (i == this.m_Owner.Controls.Count) {
                            zOrder = i;
                        }
                    }
                    this.m_Owner.Controls.Add(viewer);
                    this.m_Owner.Controls.SetChildIndex(viewer, zOrder);
                }
                catch {
                    viewer.MyMouseDown -= new MouseEventHandler(this.m_Owner.HandleMouseDown);
                    viewer.MouseUp -= new MouseEventHandler(this.m_Owner.HandleMouseUp);
                    viewer.MouseEnter -= new EventHandler(this.m_Owner.HandleSlideEnter);
                    viewer.MouseLeave -= new EventHandler(this.m_Owner.HandleSlideLeave);
                    viewer.MouseMove -= new MouseEventHandler(this.m_Owner.HandleSlideMove);

                    this.m_Owner.Controls.Remove(viewer);
                    viewer.Dispose();
                    throw;
                }

                this.m_Owner.ResumeLayout();

                RoleSynchronizer rs = new RoleSynchronizer(viewer, this.m_Owner.m_Model.Participant);
                return rs;
            }