Example #1
0
        /// <summary>
        /// Opens an object using the main thread containing a message handler.
        /// </summary>
        /// <param name="viewerObject">The object to be opened.</param>
        private void OpenObjectInForeground(object viewerObject)
        {
            try
            {
                // Activate the application when opening an object.  This is used in situations where a notification comes in while
                // another application is active.  When the user clicks on the notification widow, they will be routed to this
                // application, which then needs to be active to take the user's input.
                this.Activate();

                // Close down any documents that are currently open in the viewer.
                if (this.activeViewer != null)
                {
                    this.activeViewer.Close();
                }

                // If an object type was selected that doesn't have a viewer (or the viewer couldn't be loaded), then
                // reject the operation and leave the last viewer up.
                Viewer viewer = this.viewerTable[viewerObject.GetType()];
                if (viewer == null)
                {
                    throw new Exception("Viewer not found");
                }

                // This will synchronize the navigators with the open document.
                this.folderList.Open(viewerObject);
                this.guardianBar.Open(viewerObject);
                this.Text = viewerObject.ToString() + " - " + Properties.Settings.Default.ApplicationName;

                // This is an optimization: if the viewer for the current object is the same as the viewer for the last
                // object, then we'll skip the step of swapping the screen elements around and just reuse the current
                // viewer.  Otherwise, there's some modest reorgainization of the screen required to activate the proper
                // viewer.
                if (this.activeViewer != viewer)
                {
                    // The code below will modify the layout of the FormMain frame window.  It will swap out the current
                    // viewer its menus and toolbars and replace it with the new viewer and it's resources.  Suspending
                    // the layout will minimize the screen distractions.
                    SuspendLayout();

                    // Swap the new active viewer with the previous one.  Also, have the viewer cleared out so it's empty
                    // the next time it's activated.  This gets rid of the disturbing effect of seeing the previous data
                    // when you select a new report.  It shows up momentarily while the new document is constructed.
                    // Clearing it out now will give it a chance to create a blank report in the background.
                    viewer.BringToFront();

                    this.menuStrip.SuspendLayout();
                    this.toolStrip.SuspendLayout();

                    // Clear the previous menu and tools from the child viewer out of the main container area.
                    ToolStripManager.RevertMerge(this.menuStrip);
                    ToolStripManager.RevertMerge(this.toolStrip);

                    // Merge the container's menu with the menu of the active viewer.
                    ToolStripManager.Merge(viewer.MenuStrip, this.menuStrip);
                    ToolStripManager.Merge(viewer.ToolBarStandard, this.toolStrip);

                    this.menuStrip.ResumeLayout();
                    this.toolStrip.ResumeLayout();

                    // Let the screen process the changes.
                    this.ResumeLayout();

                    this.activeViewer = viewer;
                }

                // Opening is a somewhat involved operation.  Because it may take a few seconds to open a report, the
                // message loop can't be suspended while the user waits.  The operation is done asynchronously.  This
                // operation will kick off an asynchronous operation in the viewer that will gather all the resources
                // needed and draw the document.  When that operation is complete, the viewer will kick off an event that
                // will signal the 'Open' operation is complete.  At that point, a message will be broadcast from the
                // control and picked up by the 'viewer_EndOpenDocument' method below which will complete the operation of
                // opening the viewer and document.
                this.activeViewer.Open(viewerObject);
            }
            catch (Exception exception)
            {
                // These user interface errors need to be show to the users.
                MessageBox.Show(exception.Message, "Guardian Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
            }
        }
Example #2
0
        /// <summary>Initializes the Dynamically Loaded Viewers</summary>
        /// <remarks>
        /// The application is constructed as a container for navigators, document viewers and special purpose dialog boxes. Said
        /// differently, we want the application to be extensible and have incremental upgrades, so there's no hard coded way of
        /// saying "If I click on this icon, I want this user control displayed."  The binding between the database objects and the
        /// Viewers (special purpose user interface controls) is done dynamically through a configuration file.  The configuration
        /// file has a list of DLLs and the objects in those DLLs that can be used for viewing.  Each of the viewers or special
        /// purpose dialog boxes has an integer associated with it.  This integer is the 'type code' which corresponds to the type
        /// codes found in the 'types' table on the database.  When we get a request to open up one of these objects, we use the
        /// type code to map the 'Open' request to one of the dynamically loaded modules.  This hash table is used to associate the
        /// type code with the proper viewer.
        /// </remarks>
        public void InitializeViewers()
        {
            // The viewing area of the frame can have several viewers which all sit on top of each other in the same space. The
            // active viewer is the one that is visible and sits on top of all the rest.
            this.activeViewer = null;

            // This table contains a mapping between all the object types and the viewers used to present the data in those
            // types.  When an object is opened, this table is searched for that object's type and the viewer that is part of the
            // key pair is loaded into the viewer area and the object is opened up into that viewer.
            this.viewerTable = new Dictionary <Type, Viewer>();

            // Though a viewer can be specified to display several different types, only one instance of that viewer will be
            // created. This table helps organize the viewers during initialization so there is only one instance of a viewer for
            // the entire application.
            this.viewerTypeTable = new Dictionary <Type, Viewer>();

            // Load any dynamic viewers into the application.
            ViewerSection viewerSection = (ViewerSection)ConfigurationManager.GetSection("viewers");

            if (viewerSection != null)
            {
                // This loop will load each add-in module and associate it with an object type code.
                foreach (ViewerInfo viewerInfo in viewerSection)
                {
                    // The most likely error to catch is the dynamically loaded control doesn't exist.  In any case, a failure to
                    // load any of the add-ins is not fatal.
                    try
                    {
                        // This holds the next viewer to be initialized from the application settings.
                        Viewer viewer = null;

                        // If the specified viewer has already been created for another type, it will be re-used.  The idea here is
                        // that the viewer will have the intelligence to work out how to display any given data type.
                        if (!viewerTypeTable.TryGetValue(viewerInfo.ViewerType, out viewer))
                        {
                            viewer = (Viewer)viewerInfo.ViewerType.Assembly.CreateInstance(viewerInfo.ViewerType.ToString());
                            this.viewerTypeTable.Add(viewerInfo.ViewerType, viewer);
                        }

                        // This is where the mapping between the object type and the viewer used to display that object is kept.
                        // When a navigator selects an object, it will send it to a Viewer.  The Viewer will pull apart the data in
                        // the object and determine how to show it to the user.  But the first step is to pass the object on to the
                        // appropriate Viewer.
                        this.viewerTable.Add(viewerInfo.Type, viewer);

                        // The Viewer will fill the panel in which it is placed.
                        viewer.Dock = DockStyle.Fill;

                        // This will give the viewers a method to ask the container to open a new object.
                        viewer.ObjectOpen += new OpenObjectEventHandler(this.OpenObject);

                        // This is the panel where all the viewers will be displayed.
                        this.splitContainer2.Panel2.Controls.Add(viewer);
                    }
                    catch (Exception exception)
                    {
                        // Catch the most general errors and emit them to the debug devide.
                        string errorMessage = String.Format("Viewer {0} couldn't be loaded: {1}", viewerInfo.ViewerType, exception.Message);
                        MessageBox.Show(errorMessage, "Guardian Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }