23 Replies Latest reply on Dec 6, 2010 8:04 PM by spilon

    Using the Visual Studio designer to easily build a ProcessBook Docking Window

      As you may already know, we provide templates to develop PI ProcessBook 3.x .NET Add-Ins (they were explained in this webinar and are available on the vCampus Download Center). This post is related to one of those 4 templates: the Docking Window Add-In.

       

      In the Visual Studio 2005 version of this template, a PBControlView object named ctrlView is added to the docking window (m_dockWindow variable in the Connect class). On this view, a label is then created:

      ctrlView.CreateControl("{978C9E23-D4B0-11CE-BF2D-00AA003F40D0}")
        //or
      ctrlView.CreateControl("Forms.Label.1")

       

      ----> Yes, you are right: this is a COM control, not a .NET one!
      ----> And yes, you are right again: we are not using the Form/UserControl designer provided in Visual Studio, which most people are using on a regular basis.

       

       

       

      The good news is: there is a way for you to easily design a .NET UserControl with the Visual Studio designer and then have the docking window load it. Here's how you can do this in 5 simple steps:

       

      1. Add a .NET User Control to your VB.NET or C# add-in project
      090610_2D00_UserControlInPBDockWindow1.jpg

       

      2. Double-click on the User Control in the Solution Explorer - you'll get in design mode.

       

      3. Resize the User Control, add the controls (and the code) you want
        (Hint: if you have a control which you want to occupy the whole docking window (e.g. TreeView), you can "dock it in the parent container" as shown in the screenshot below. That way you don't have to write code to handle resizing of the docking window by the user in ProcessBook )
      090610_2D00_UserControlInPBDockWindow2.jpg

       

      4. Jump in the code for your User Control and make it visible to COM
      (Remember: PI ProcessBook is COM-based... which means that under the hood, the PBControlView.CreateControl method - which we'll use in the next step) expects to create COM controls)

       

          In VB.NET:
          090610_2D00_UserControlInPBDockWindow3.jpg

       

          In C#:
          090610_2D00_UserControlInPBDockWindow4.jpg

       

      5. Back to the code in the OnConnection method of the Connect class, get the PBControlView to load that ".NET-but-COM-visible control"
      (and keep a reference to it for future usage:

       

          In VB.NET:   

      Dim usrCtrl As UserControl1 = DirectCast( _
          ctrlView.CreateControl("AddinPBDockWin_VB1.UserControl1"), UserControl1)

       

          In C#:    

      UserControl1 usrCtrl = 
              (UserControl1)ctrlView.CreateControl("AddInPBDockWin_CS1.UserControl1");

       

      Hope this helps!

        • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window
          dhollebeek

          We (PB development) used to create UserControls in OnConnection and no longer do this due to performance issues.  UserControls unfortunately take about 1 second to create, so if you have 10 add-ins you are adding 10 seconds to the PB start time.  This is fine if all the dockwindows are visible, but it's a waste if most of them are hidden or pinned.  All the "official" PB add-ins now have implement the EPBDockWindow interface in their Connect classes.  Then when the EPBDockWindow.Show event is fired, we create the user control at that time if it hasn't been created yet.  In C#, just inherit from EPBDockWindow in your Connect class then right click on it and select Implement Interface and then add the following code to the Show method that Visual Studio writes for you:

          private bool initted;

          public void Show(bool Show, bool Pinned)
          {
              if (Show && !initted)
              {
                  initted = true;
                  UserControl1 usrCtrl = ctrlView.CreateControl("AddinPBDockWin_CS1.UserControl1") as DockWindowControl;
              }
          }

            • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window
              owluser

               2 Questions:

               

              Do you have sample code for how to implement the EPBDockWindow interface in VB?

               

              And, How do I create an Event Trigger that fires when a DockWindow is ReSized or "pops up" when Pinned?

               

              My UserControl in my DockWindow Draws Objects (Ellipses, Pies, Rectangles, etc) via a Timer update, but I need to ReDraw these objects whenever the above two events occur.   The drawn objects aren't "persistant" so they appear to be "erased" whenever the DockWindow renders.  In fact, on the UserControl "Load" event, these objects seem to be drawn and then "erased" until the Timer Event triggers a redraw.

                • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window

                  @Andy Holmes: I would like to kindly invite you to initiate new discussion threads when you have new questions - e.g. one for the "EPBDockWindow interface" question and one for the "Resize/Popup events" question.

                   

                  Right now these are buried deep in another discussion topic, which decreases your chances or people seeing (and answering) it, and other readers' chances of finding the answers when they have the same questions.

                   

                  Hope this helps!

                  • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window
                    dhollebeek

                    Andy Holmes

                     2 Questions:

                     

                    Do you have sample code for how to implement the EPBDockWindow interface in VB?

                     

                    And, How do I create an Event Trigger that fires when a DockWindow is ReSized or "pops up" when Pinned?

                     

                    My UserControl in my DockWindow Draws Objects (Ellipses, Pies, Rectangles, etc) via a Timer update, but I need to ReDraw these objects whenever the above two events occur.   The drawn objects aren't "persistant" so they appear to be "erased" whenever the DockWindow renders.  In fact, on the UserControl "Load" event, these objects seem to be drawn and then "erased" until the Timer Event triggers a redraw.

                     

                     

                    1.  No I don't have any sample code.

                     

                    2.  What you probably want to do is just sign up for the Show event (it's the only event in that interface).  If you are in C# it's the usual DockWindow.Show += eventhandler syntax.  In VB, use the WithEvents keyword in the Dim statement.  Then the event handler will get called any time the visibility or floating state of the window changes.  Sometimes I also create a handler for UserControl.Resize which also fires in many circumstances.

                      • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window

                        @Andy Holmes: hopefully David's answer about the PBDockWindow.Show event is what you were looking for. As far as "implementing the interface", I am not sure why you would implement this your own as opposed to use our own implementation of the docking window... can you shed some light on this?

                         

                        Plus that might help coming up with sample code (if you still need it after the previous answer)... it's difficult to put something together when you don't know what needs to be accomplished.

                  • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window

                     

                     

                    Steve I've followed your suggestion and I'm successfully getting a test container built. But loading it into Processbook 3.1 fails as an addin. Any suggestions. I'm using VB.NET in VS2008.

                     

                     

                     

                     PB_5F00_ErrorDialog-Can_2700_t-load-Addin.bmp

                     

                     

                     

                    UserControl1.bmp

                      • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window

                        Well there's a variety of reasons why an add-in might not load in a produc...  best I can suggest is to try to debug it and see which line of code is guilty. Simply go in your project properties, go under Debug, select "Start external program:" and specify the path to your PI ProcessBook application (....\PIPC\Procbook\Procbook.exe).

                         

                        090710_2D00_ProjectProperties_2D00_Debug.jpg

                         

                        Then hit F5 to start the project and watch it run crash

                         

                        If it doesn't even get in the code, then it might be a problem with how it's registered in the Windows Registry. Make sure you have the appropriate keys in there, and that you have a unique GUID in your code. The AddinReg.reg contains the information that needs to go in the Registry and this discussion thread discusses the creation of a new GUID for your add-in.

                         

                        Hope this helps!

                          • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window

                            Steve and Michael,

                             

                            This is great info, but I'm still not getting the add-in to load.

                             

                            I'm now getting another error. I added a unique GUID and registered it using RegAsm. I have the addin in the registry. I now get another error when I try to run the application. See the error list below.  

                             

                            Add_2D00_In-Manager.bmp

                             

                            ErrorList.bmp

                             

                             

                             

                            Below is my VB.NET code

                             

                             

                             

                             

                             

                            Option Explicit On

                            Imports Extensibility
                            Imports System.Runtime.InteropServices

                            <GuidAttribute("48629B4B-05C7-4074-9AE3-5F89D2ECC476"), ProgIdAttribute("AmgenSuccessRateAddin.Connect")> _
                            Public Class Connect
                                Implements Extensibility.IDTExtensibility2, IDisposable

                                Dim m_App As PBObjLib.Application
                                Dim m_strDSName As String = "AmgenSuccessRateAddin"

                            #Region "docking window"
                                Dim m_dockWindow As PBObjLib.PBDockWindow
                            #End Region

                                Public Sub Dispose() Implements IDisposable.Dispose
                                    Exit Sub
                                End Sub

                                Public Sub OnBeginShutdown(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnBeginShutdown

                                End Sub

                                Public Sub OnAddInsUpdate(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnAddInsUpdate

                                End Sub

                                Public Sub OnStartupComplete(ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnStartupComplete

                                End Sub

                                Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnDisconnection

                                    m_dockWindow = Nothing
                                    m_App = Nothing

                                End Sub

                                Public Sub OnConnection(ByVal application As Object, ByVal connectMode As Extensibility.ext_ConnectMode, ByVal addInInst As Object, ByRef custom As System.Array) Implements Extensibility.IDTExtensibility2.OnConnection

                                    On Error GoTo error_handler
                                    m_App = CType(application, PBObjLib.Application)

                                    ' BEGIN docking window code
                                    m_dockWindow = m_App.DockWindows.Add(PBObjLib.pbDockWindowType.pbTypeSingleViewWindow, "Simple Docking Window", PBObjLib.pbDockPosition.pbDockLeft, False)

                                    If Not (m_dockWindow Is Nothing) Then
                                        m_dockWindow.Visible = True
                                        m_dockWindow.Width = 250

                                        ' add objects to the docking window here
                                        ' for example, add a label control
                                        Dim ctrlView As PBObjLib.PBControlView = CType(m_dockWindow.Views.Add(PBObjLib.pbViewType.pbControlViewType, "Search"), PBObjLib.PBControlView)
                                        Dim usrCtrl As UserControl1 = DirectCast(ctrlView.CreateControl("AddinPBDockWin_VB1.UserControl1"), UserControl1)

                                        Dim labcntrl As Object = ctrlView.CreateControl("{978C9E23-D4B0-11CE-BF2D-00AA003F40D0}")
                                        labcntrl.Caption = "My Docking Window Example"
                                    End If
                                    ' END Docking window code

                                    Exit Sub

                            error_handler:
                                    MsgBox("Exception on Connection:" + Err.Description)

                                End Sub

                            End Class

                             

                             

                              • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window
                                mweiss

                                Jon Croonenberghs

                                I'm now getting another error. I added a unique GUID and registered it using RegAsm. I have the addin in the registry. I now get another error when I try to run the application.

                                 

                                I think you're using the same GUID for the Connect class and the Assembly. Change one of them to a new unique GUID. The assembly's GUID can be changed in AssembyInfo.vb or via My Project>Application>Assembly Information.

                                  • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window

                                    In VS2008 VB.NET I am now have the GUIDs all set right. We I debug the application in the OnConnection Class I get the error Control not found when

                                    Dim usrCtrl As UserControl1 = 
                                    DirectCast(ctrlView.CreateControl("PBAddin_AmgenUnitOpSuccessRate.UserControl1"), UserControl1)
                                    is called.

                                     

                                    The PBAddin_AmgenUnitOpSuccessRate does come up in Processbook but it is empty. I'm close.

                                     

                                    OnConnect.bmp

                                      • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window
                                        mweiss

                                        You are close! You are past the hurdles of add-in loading, now you need to get the ProcessBook to load your docking window control. The contents of a docking window takes the form of an COM ActiveX control. Much like how we load the connect class, ProcessBook uses the Program ID of the ActiveX control to create the UI of the docking window. To make a long and super technical story short an ActiveX control is a basic COM object (just like your Connect class) that includes all sorts of extra bits to make a user interface that can be embedded in other applications. (ActiveX = COM+UI)

                                         

                                        .NET makes it easy to turn a UserControl into an ActiveX control. Just like you can make a normal COM object out of a .NET any class using class attributes, you can make an ActiveX control the same way out of a UserControl derived class. While Steve suggested in the begining of this discussion to use COMVisible = true to make this happen, I've never used that attribute (but I sure it works - I just don't know the details of it). Looking at a standard ProcessBook add-in (Details) we use GUIDAttribute and ProgId just like we did for the add-in's main Connect class. Since .NET knows this is UserControl it will make this a full-blown ActiveX control out of it. 

                                         

                                        Replace COMVisible attribute on your UserControl1 class with:

                                        [GuidAttribute("XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"), 
                                          ProgId("PBAddin_AmgenUnitOpSuccessRate.UserControl1")]

                                        Sorry for the C# syntax - let me know if you need help with the VB. The X's would be a new GUID, for a total of 3 unique GUIDs for your addin (Connect, UserControl1, and the assembly itself). Rebuilding should add all the stuff into the registry needed for PB to load "BAddin_AmgenUnitOpSuccessRate.UserControl1".

                                         

                                        As an aside, I'd rename the control to something other than "UserControl1".

                                          • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window

                                            Success! I have a VB.NET VS2008 Template that I can work with. Thanks Michael for your insight into building this tool. The next steps will be to build a viable add-in and then learn how to deploy the add-in to my users.

                                             

                                            Replacing COMVisible w/ GuidAttribute enable the add-in to load.

                                            <GuidAttribute("8E8B632F-C774-48c6-BE88-A96152FB690D"), _
                                              ProgIdAttribute("PBAddin_AmgenUnitOpSuccessRate.Connect")> _

                                            Public Class Connect .....................

                                              • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window

                                                Now I have funtional addin on my machine. What would be the steps or tool to use to install this on other systems. I copied the dll and registered (RegAsm) it on another system, updated the registry for the addin but Processbook fails to load the addin.

                                                 

                                                 PBAddin_5F00_AmgenUnitOpSuccessRate.bmpa

                                                  • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window

                                                    Do you have the same version of PI ProcessBook installed on both machines?
                                                      And how about the version of the .NET Framework?
                                                      And the version of any other references you may use in that project (PI SDK, AF SDK, others...)?

                                                     

                                                    Also, did you ever copy an earlier version of that DLL on that machine before to move this one?

                                                      • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window

                                                        Both machines have the current version of ProcessBook. Both have .NET Framework 3.5 and PI SDK. Both System's OS is XP.

                                                         

                                                        I have successfully registered the dll  with RegAsm.

                                                         

                                                         

                                                          • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window
                                                            mweiss

                                                            Let's try troubleshooting .NET assembly loading. Search a machine with Visual Studio installed for FUSLOGVW.exe. Copy this program to the other machine with the problem.

                                                            1. Run it - you should see the Assembly Binding Log Viewer
                                                            2. Press the Settings...button and select Log binds failures to disk
                                                            3. Press OK
                                                            4. Run ProcessBook
                                                            5. If the add-in is still loading on startup you'll see that "cannot load add-in, remove?" message. Skip to Step 7 if you see this error.
                                                            6. If the add-in is not auto-loading, go to tools>add-ins and load it (which won't work, you should see an error)
                                                            7. Press the Refresh button on the Assembly Binding Log Viewer.  You should see
                                                            8. Post the results on this vcampus thread. You'll have to select each entry in the list can press View Log. Copy and Paste the HTML log that it shows into your reply.
                                                            9. Press the Settings...button and select Log disabled.
                                                            10. Close PB and Fuzelogvw.

                                                            Fuselogvw can be finicky - hopefully it'll work. If (in step 7) pressing Refresh shows nothing repeat the test but in step 2 select Log all binds to disk. See if anything appears after you press Refresh. Don't attempt to send us the results in this case, since you'll see ALOT of entries (if fuzelog is working that is).

                                                              • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window

                                                                I used the FUSLOGVW.EXE to view the log file see below:

                                                                 

                                                                *** Assembly Binder Log Entry  (8/31/2009 @ 1:32:56 PM) ***

                                                                 

                                                                The operation failed.
                                                                Bind result: hr = 0x80070002. The system cannot find the file specified.

                                                                 

                                                                Assembly manager loaded from:  C:\WINNT\Microsoft.NET\Framework\v2.0.50727\mscorwks.dll
                                                                Running under executable  C:\Program Files\PIPC\Procbook\Procbook.exe
                                                                --- A detailed error log follows.

                                                                 

                                                                === Pre-bind state information ===
                                                                LOG: User = AM\jcroonen
                                                                LOG: DisplayName = PBAddin_AmgenUnitOpSuccessRate, Version=1.1.3511.24282, Culture=neutral, PublicKeyToken=null
                                                                 (Fully-specified)
                                                                LOG: Appbase = file:///C:/Program Files/PIPC/Procbook/
                                                                LOG: Initial PrivatePath = NULL
                                                                LOG: Dynamic Base = NULL
                                                                LOG: Cache Base = NULL
                                                                LOG: AppName = NULL
                                                                Calling assembly : (Unknown).
                                                                ===
                                                                LOG: This bind starts in default load context.
                                                                LOG: No application configuration file found.
                                                                LOG: Using machine configuration file from C:\WINNT\Microsoft.NET\Framework\v2.0.50727\config\machine.config.
                                                                LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
                                                                LOG: Attempting download of new URL file:///C:/Program Files/PIPC/Procbook/PBAddin_AmgenUnitOpSuccessRate.DLL.
                                                                LOG: Attempting download of new URL file:///C:/Program Files/PIPC/Procbook/PBAddin_AmgenUnitOpSuccessRate/PBAddin_AmgenUnitOpSuccessRate.DLL.
                                                                LOG: Attempting download of new URL file:///C:/Program Files/PIPC/Procbook/PBAddin_AmgenUnitOpSuccessRate.EXE.
                                                                LOG: Attempting download of new URL file:///C:/Program Files/PIPC/Procbook/PBAddin_AmgenUnitOpSuccessRate/PBAddin_AmgenUnitOpSuccessRate.EXE.
                                                                LOG: All probing URLs attempted and failed.

                                                                 

                                                                Based on what was in the log file I could determine the add in files need to be the /PIPC/Processbook directory.

                                                                 

                                                                Having Interop.PBObLib.dll, PBAddin_AmgenUnitOpSuccessRate.dll and PBAddin_AmgenUnitOpSuccessRate.tlb in  /PIPC/Processbook directory enabled the add-in to load and function.

                                                                 

                                                                 

                                                                  • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window
                                                                    MichaelvdV@Atos

                                                                    I found a nice way to use WPF in your Procesbook addin. I have tested and used this with VS 2010 / .NET 4

                                                                    
                                                                    

                                                                      [ComVisible(true)]
                                                                        public partial class MainControl : UserControl
                                                                        {
                                                                            public MainControl()
                                                                            {
                                                                                InitializeComponent();
                                                                                this.Load += MainControl_Load;
                                                                            }

                                                                            void MainControl_Load(object sender, EventArgs e)
                                                                            {
                                                                                ElementHost host = new ElementHost()
                                                                                {
                                                                                    Dock = DockStyle.Fill,
                                                                                    Child = new SearchControl(),
                                                                                };
                                                                                this.Controls.Add(host);
                                                                            }
                                                                        }

                                                                     

                                                                    It's very simple, but in this case the only way. The basic thought is that you host your WPF control (in this case 'SearchControl') inside Windows Forms. I have tried to use the WPF Control immediatly as a PB Addin, but this doesn't work (one or more of the parent objects of UserControl in WPF have ComVisible set to false).

                                                                     

                                                                    You can use the standard Docking Window Template provided by OSIsoft, add a new WPF control, add a new WinForms control. Let the Connect method instantiate the WinForms Control (which in turn hosts the WPF control). You then have to add a few references to support WPF in your project (Visual Studio will tell you which).

                                                                     

                                                                    Using XAML and WPF to create PB addins is great by the way :)

                                              • Re: Using the Visual Studio designer to easily build a ProcessBook Docking Window
                                                mweiss

                                                I'm not sure why this is happening but maybe I can clarify how ProcessBook loads add-ins. Maybe this will help? By the way, did this add-in ever load in ProcessBook?

                                                 

                                                All of this is based on COM, all add-ins regardless of programming language are using COM (be it VB6, .NET, C++, Delphi, etc...). Exactly how you coerce your language of choice to make a COM object is another story... We provide VB6 (I assume we still support this?), C#, and VB.NET project templates to make it easier to get started.

                                                 

                                                A ProcessBook add-in consists of, at its most basic level, as a single COM object. This COM object must support one COM interface IDTExtensibility2. Our Visual Studio templates name this COM object as "Connect". It'll be derived from IDTExtensibility2 which forces the class to implement these methods:
                                                •    OnAddInsUpdate
                                                •    OnBeginShutdown
                                                •    OnConnection
                                                •    OnDisconnection
                                                •    OnStartupComplete

                                                 

                                                This COM object is NOT the ActiveX control used in the docking windows - that is a different COM object and my guess not part of your problem.
                                                ProcessBook will load the connect object using something in COM called the Program ID (or PROGID). (This is a string and not a GUID.) ProcessBook gets the list of add-ins (and their associated PROGIDs) from the registry here:
                                                HKEY_LOCAL_MACHINE\Software\PISystem\PI - ProcessBook\Addins\<PROGIDs>

                                                 

                                                The PROGID usually look like this "<projectname>.Connect"

                                                 

                                                This information is automatically added to the registry by our Visual Studio templates. See the file AddInReg.reg. When deploying you add-in to other machines (not the development machine) you'll have to add these registry settings yourself.

                                                 

                                                This step 1 - ProcessBook finds the PROGID of each add-in from the registry. Step 2 is to load the COM object using the PROGID. This done for us by the COM APIs of Windows.

                                                 

                                                For COM to load an object by its PROGID a whole mess of registry entries need to be present. Thankfully most of these settings will be added by .NET for us. Visual Studio will add them when you build the project. On other machines you have to run the regasm.exe command-line tool yourself (it’s like .NET version of regsvr32.exe which you may have used before – why Microsoft decided to have .NET COM object not support regsvr32 is beyond me?!). Mine was here:
                                                C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\RegAsm.exe

                                                 

                                                The syntax is simple: regasm <assembly.dll>

                                                 

                                                This exposed any .NET class inside the assembly as a COM object if it's marked as such. This magic is for the Connect class is performed by these class-level attributes(C# syntax):
                                                [GuidAttribute("17b690ba-5811-485d-8f80-706b4a759934"), ProgId("<projectname>.Connect")]

                                                 

                                                A search in you registry for "<projectname>.Connect" will show you some of this COM registration info for you COM object Visual Studio/regasm adds.

                                                 

                                                Once COM loads the object for ProcessBook, initialization code inside the COM object will be run. At this point all sorts of things can go wrong. In the .NET world a common issue is bad or missing .NET assembly references. This is hard to pin down – often temporarily removing references and commenting suspect code, rebuilding, and retrying in ProcessBook can narrow down where the problem is. A slightly different approach would be to create a new add-in and start re-adding your code back in one feature at a time until it fails.