9 Replies Latest reply on Sep 11, 2013 4:31 PM by tseiferth

    Could use some AF controls samples/help

    seneschal

      I am not really picking up from the help files how to do these things so I am hoping someone will post some sample code, or directions.  

       

      I am looking into the various VS2012 controls that PI makes available, and I am trying to do the following.

       

      - Create a AFDatabasePicker and a AFTreeView on a WinForm.

       

      - Populate the database picker drop down control with the available AF databases.

       

      - Once a AF database is selected, populate the treeview with the same stuff you see in PI System Explorer

       

      - And clicking on a node would yield an object to work with (AFElement if they clicked on an Element, etc)

       

      I'm sure this is all very easy. but I've been sifting though control documentation for a while and can't quite get it.

       

      Thanks!

       

      Dave

        • Re: Could use some AF controls samples/help
          pkaiser

          Assuming you've created a new Windows Forms application in Visual Studio 2012, the first thing you need to do is add references to the AF SDK and the AF UI components. To do this, in Solution Explorer, right click the References folder for your solution, and select Add Reference... from the resulting popup menu. This will result in display of the Reference Manager dialog. Expand the Assemblies section on the left, and click on Extensions. Scroll down the list of Extensions until you find OSIsoft.AF.UI and OSIsoft.AFSDK, and check the boxes for both (make sure you get the 4.0.0.0 versions):

           

          8512.References.png

           

          Click OK to add references to both of these assemblies to your project:

           

          1586.RefsInProj.png

           

           

           

          Before adding instances of the AFDatabasePicker and AFTreeView to your Form, first add these controls to the Toolbox. With your Form designer open, expand the Toolbox by clicking its tab on the left side of Visual Studio, or by selecting the VIEW > Toolbox menu. Right click in the Toolbox and select Choose Items... in the resulting popup menu to invoke the Choose Toolbox Items dialog. Select the .NET Framework Components tab, and scroll through the list of components until you find the AFDatabasePicker and AFTreeView controls (they might be easier to find if you sort by Namespace). Check the boxes for both (make sure you get the 4.0.0.0 versions), then click the OK button to add them to the Toolbox:

           

          0525.TboxItems.png

           

          (The picture above only shows AFDatabasePicker, but you must also check the box for AFTreeView)

           

          Now both of these controls should be available in the Toolbox:

           

          3051.tbox.png

           

           

           

          Drag one instance of each of these controls onto your form. If you resize your Form a bit, it should look something like this:

           

          3716.BlankForm.png

           

           

           

          Now we start writing code! Double-click on a blank part of the Form to open the code window. This should create a Load method for the Form similar to this:

           

                  private void Form1_Load(object sender, EventArgs e)
                  {
                      
                  }
          

          First, at the top of the Form code add two Using statements to the list already there; one for OSIsoft.AF, and one for OSIsoft.AF.UI:

           

          using OSIsoft.AF;
          using OSIsoft.AF.UI;
          

          Without a PISystemsPicker control on your Form, you'll have to write code to assign a PISystem to the AFDatabasePicker, so it knows from which PISystem to get the list of available AFDatabases. For simplicity's sake, you can just use the default PISystem. This is accomplished by invoking the SetPISystem method on the AFDatabasePicker. When you invoke SetPISystem, you also specify which AFDatabase should be selected by default -- again, for simplicity, you can use the default AFDatabase for the default PISystem:

           

                  private void Form1_Load(object sender, EventArgs e)
                  {
                      PISystems systems = new PISystems();
                      afDatabasePicker1.SetPISystem(systems.DefaultPISystem, systems.DefaultPISystem.Databases.DefaultDatabase);
                  }
          

          At this point, if you click the Start button in Visual Studio, you should now be able to interact with the AFDatabasePicker, choosing between the different AFDatabases on the default PISystem. Initially, the default AFDatabase for the default PISystem will be selected. You can also click the ellipsis button ("...") in the AFDatabasePicker to switch to a different PISystem. Click the close box on the Form to stop debugging and return to edit mode.

           

          The next step is to connect the AFDatabasePicker to the AFTreeView. With the Form designer open, right-click the AFDatabasePicker and select Properties from the resulting popup menu. In the Properties pane, click the Events button in the toolbar at the top to display the list of available events for the AFDatabasePicker. Double-click the SelectionChange event to switch to the code window for the Form and generate a shell for the SelectionChange event that will look like this:

           

                  private void afDatabasePicker1_SelectionChange(object sender, OSIsoft.AF.UI.SelectionChangeEventArgs e)
                  {
                      
                  }
          

          Every time the selected AFDatabase in the AFDatabasePicker changes, this method will be invoked. Add code to this method to set the root of the AFTreeView to the new selection:

           

                  private void afDatabasePicker1_SelectionChange(object sender, OSIsoft.AF.UI.SelectionChangeEventArgs e)
                  {
                      afTreeView1.AFRoot = afDatabasePicker1.AFSelection;
                  }
          

          Click the Start button in Visual Studio to see the AFDatabasePicker work with the AFTreeView. Initially, you will see a hierarchy for the default AFDatabase of the default PISystem. If you change to another AFDatabase with the AFDatabasePicker control, the SelectionChange event will update the AFTreeView with the new hierarchy. You can expand and collapse the hierarchy. Click the close button on the Form to stop debugging and return to edit mode.

           

          Finally, to act upon the selected member of the hierarchy in the AFTreeView, you can use the AFSelection property of that control. For example, add a Button from the toolbox to the Form, and double-click the button to open the code window and create the shell for the Click event of the button. Use the MessageBox class to display the name of the selected item in the AFTreeView when the button is clicked like this:

           

                  private void button1_Click(object sender, EventArgs e)
                  {
                      MessageBox.Show(afTreeView1.AFSelection.ToString());
                  }
          

          There are many other ways to approach this same problem, but this simple example should get you started on what you're looking for. Here's all of the code for the Form:

           

          using System;
          using System.Collections.Generic;
          using System.ComponentModel;
          using System.Data;
          using System.Drawing;
          using System.Linq;
          using System.Text;
          using System.Threading.Tasks;
          using System.Windows.Forms;
          using OSIsoft.AF;
          using OSIsoft.AF.UI;
          
          namespace WindowsFormsApplication1
          {
              public partial class Form1 : Form
              {
          
                  public Form1()
                  {
                      InitializeComponent();
                  }
          
                  private void Form1_Load(object sender, EventArgs e)
                  {
                      PISystems systems = new PISystems();
                      afDatabasePicker1.SetPISystem(systems.DefaultPISystem, systems.DefaultPISystem.Databases.DefaultDatabase);
                  }
          
                  private void afDatabasePicker1_SelectionChange(object sender, OSIsoft.AF.UI.SelectionChangeEventArgs e)
                  {
                      afTreeView1.AFRoot = afDatabasePicker1.AFSelection;
                  }
          
                  private void button1_Click(object sender, EventArgs e)
                  {
                      MessageBox.Show(afTreeView1.AFSelection.ToString());
                  }
              }
          }
          
          1 of 1 people found this helpful
            • Re: Could use some AF controls samples/help
              seneschal

              Thank you, that was above and beyond the call... much appreciated.  

                • Re: Could use some AF controls samples/help
                  Lonnie Bowling

                  Yes, I agree, outstanding post!

                   

                  Paul, I have this large many man-month project coming up. If I post the details here would you provide me with the source code?  

                   

                  You are awesome!

                   

                  Lonnie

                    • Re: Could use some AF controls samples/help
                      pkaiser

                      Thanks guys. And Lonnie, I'd like to hear more about your big project, but no promises on source code ;)

                       

                      There are some good examples in the AFUIRef.chm that you get on vCampus with the PI AF Developer Tools download, but they only show the code and not the Form, and they're not step-by-step -- you only get the end result. But as you become more comfortable with the controls, these examples should become more useful to you.

                        • Re: Could use some AF controls samples/help
                          Marcos Vainer Loeff

                          Hello Dave,

                           

                          Please also take a look at this webinar and its source code. Although this webinar is from 2009, I am sure it would be very helpful to you!

                            • Re: Could use some AF controls samples/help
                              seneschal

                              I am looking to see if it is possible to work with the AFTreeView in such a way that I could inherit the class and add/change functionality, such as:

                               

                              - Add right-click menu items for tree view nodes, and define event handlers for them (basically add add'l menu items under the existing ones that pop up

                               

                              - Or, replace the menus that pop up with ones of my own

                               

                              - Possibly hide some functionality, such as certain unneeded branches in the tree, and perhaps certain right click menu selections to limit the scope of my app

                               

                              I do not know how I would get access to the menu object and modify it in code to add more menu items...

                               

                              Is such a thing possible, or do I have to develop my own tree view control?  If I do, is there a set of classes to use that would make building my own tree easier?

                               

                              Thanks!

                                • Re: Could use some AF controls samples/help
                                  pkaiser

                                  You can use the ContextMenuStrip property of the AFTreeView to replace the built-in popup menu with your own. On a windows form where you have an instance of AFTreeView, add an instance of the ContextMenuStrip (System.Windows.Forms.ContextMenuStrip). You can just drag one from the toolbox and drop it on your form. Use the designer to configure this context menu as you want it to appear (or write the code to configure it), and then assign it by name to the ContextMenuStrip property of your tree. Here's an example of Form_Load where I configure my AFTreeView to show the default database from my default PI System, then assign my own context menu to the AFTreeView:

                                   

                                   

                                   
                                          private void Form1_Load(object sender, EventArgs e)
                                          {
                                              PISystems systems = new PISystems();
                                              afTreeView1.AFRoot = systems.DefaultPISystem.Databases.DefaultDatabase;
                                              afTreeView1.ContextMenuStrip = contextMenuStrip1;
                                          }
                                  

                                   

                                   

                                  Each menu item that you add to your context menu strip has a click event, where you can add the code to respond to that menu item being clicked. I added two menu items to my menu strip, one called "Hello World!" and one called "Show Selection". The code for the Hello World menu item simply displays that text in a message box:

                                   

                                   

                                   
                                          private void helloWorldToolStripMenuItem_Click(object sender, EventArgs e)
                                          {
                                              MessageBox.Show(@"Hello World!");
                                          }
                                  

                                   

                                   

                                  The code for Show Selection gets the name of the currently-selected node in my AFTreeView and displays it's name in a message box:

                                   

                                   

                                   
                                          private void showSelectionToolStripMenuItem_Click(object sender, EventArgs e)
                                          {
                                              MessageBox.Show(afTreeView1.SelectedNode.Text.ToString());
                                          }
                                  

                                   

                                   

                                   

                                    • Re: Could use some AF controls samples/help
                                      seneschal

                                      I did not expect to be able to replace the menu so easily, cool.  Thanks Paul.  I keep waiting to find something that will require me to build my own tree, but so far, so good!

                                        • Re: Could use some AF controls samples/help
                                          tseiferth

                                          If you're still interested there's an example in the AFUIRef help (AF UI development help file) to show how you can add your own menu items to the existing AF menu in the tree. Here's the particular example:

                                           

                                          using System;

                                           

                                           2using System.Collections.Generic;

                                           

                                           3using System.ComponentModel;

                                           

                                           4using System.Data;

                                           

                                           5using System.Drawing;

                                           

                                           6using System.Linq;

                                           

                                           7using System.Text;

                                           

                                           8using System.Windows.Forms;

                                           

                                           9using OSIsoft.AF;

                                           

                                          10using OSIsoft.AF.Modeling;

                                           

                                          11using OSIsoft.AF.Analysis;

                                           

                                          12using OSIsoft.AF.UI;

                                           

                                          13

                                           

                                          14namespace UIControls

                                           

                                          15{

                                           

                                          16    /// <summary>

                                           

                                          17    /// A form containing an AFTreeView control.

                                           

                                          18    /// </summary>

                                           

                                          19    /// <remarks>

                                           

                                          20    /// Shows the use of two AFTreeView event handlers (AFSelect and MenuItemClicked) as well as show properties.

                                           

                                          21    /// </remarks>

                                           

                                          22    public partial class TreeViewForm : Form

                                           

                                          23    {

                                           

                                          24        // Used for proprietary menu items.

                                           

                                          25        private const int kMenuStart = 0x3000;

                                           

                                          26        // An example of a proprietary menu option.

                                           

                                          27        private const int kMenuCommandProprietary = kMenuStart + 1;

                                           

                                          28

                                           

                                          29        // The form containing an AFTreeView control.

                                           

                                          30        public TreeViewForm()

                                           

                                          31        {

                                           

                                          32            InitializeComponent();

                                           

                                          33

                                           

                                          34            // Listen for selection changes on the tree (Note: this can be armed through the designer).

                                           

                                          35            afTreeView.AfterSelect += new TreeViewEventHandler(afTreeView_AfterSelect);

                                           

                                          36

                                           

                                          37            // Listen for menu item clicked on the tree (Note: this can be armed through the designer).

                                           

                                          38            afTreeView.MenuItemClicked += new MenuItemClickedEventHandler(afTreeView_MenuItemClicked);

                                           

                                          39        }

                                           

                                          40

                                           

                                          41        // Occurs after the tree node is selected. Inherited from TreeView.

                                           

                                          42        void afTreeView_AfterSelect(object sender, TreeViewEventArgs e)

                                           

                                          43        {

                                           

                                          44            // Cast the tree node to an AFTreeNode.

                                           

                                          45            AFTreeNode node = e.Node as AFTreeNode;

                                           

                                          46

                                           

                                          47            // Get the AFObject from the AF tree node and display it to the debugger's output window.

                                           

                                          48            if (node != null && node.AFObject != null)

                                           

                                          49                System.Diagnostics.Debug.WriteLine("Current AF object=" + node.AFObject.ToString());

                                           

                                          50        }

                                           

                                          51

                                           

                                          52        // Occurs before a form is displayed for the first time.

                                           

                                          53        protected override void OnLoad(EventArgs e)

                                           

                                          54        {

                                           

                                          55            base.OnLoad(e);

                                           

                                          56

                                           

                                          57            // The examples below show how to hide specific AF object types in the tree.

                                           

                                          58            // Uncomment the following to hide the AF plug-ins in the tree.

                                           

                                          59            // Hide the plug-ins.

                                           

                                          60            //afTreeView.ShowPlugIns = false;

                                           

                                          61            // Show the element attributes.

                                           

                                          62            //afTreeView.ShowAttributes = true;

                                           

                                          63

                                           

                                          64            // Get the list of PI systems.

                                           

                                          65            PISystems systems = new PISystems();

                                           

                                          66

                                           

                                          67            // Set the tree view's root to the default PI system.

                                           

                                          68            afTreeView.AFRoot = systems.DefaultPISystem;

                                           

                                          69

                                           

                                          70            // Add event handlers for the AF menu object uses as the AF tree view's context menu strip.

                                           

                                          71            // Use these events to override visibility, to disable an item, add a menu item, or handle the item clicked.

                                           

                                          72            AFMenu afmenu = afTreeView.ContextMenuStrip as AFMenu;

                                           

                                          73            if (afmenu != null)

                                           

                                          74            {

                                           

                                          75                // Event raised before menu control is opening.

                                           

                                          76                afmenu.BeforeOpening += new CancelEventHandler(afmenu_BeforeOpening);

                                           

                                          77                // Event raised when the menu control is opening.

                                           

                                          78                afmenu.Opening += new CancelEventHandler(afmenu_Opening);

                                           

                                          79                // Event raised when the menu is opened.

                                           

                                          80                afmenu.Opened += new EventHandler(afmenu_Opened);

                                           

                                          81            }

                                           

                                          82        }

                                           

                                          83

                                           

                                          84        // Event raised before menu control is opening.

                                           

                                          85        void afmenu_BeforeOpening(object sender, CancelEventArgs e)

                                           

                                          86        {

                                           

                                          87            // Get the AF menu.

                                           

                                          88            AFMenu afmenu = sender as AFMenu;

                                           

                                          89            if (afmenu != null)

                                           

                                          90            {

                                           

                                          91                // Uncomment the following to cancel the menu display.

                                           

                                          92                //e.Cancel = true;

                                           

                                          93            }

                                           

                                          94        }

                                           

                                          95

                                           

                                          96        // Event raised when the menu control is opening.

                                           

                                          97        void afmenu_Opening(object sender, CancelEventArgs e)

                                           

                                          98        {

                                           

                                          99            // Get the AF menu.

                                           

                                          100            AFMenu afmenu = sender as AFMenu;

                                           

                                          101            if (afmenu != null)

                                           

                                          102            {

                                           

                                          103                // Add your item to the menu if it doesn't already exist.

                                           

                                          104                ToolStripMenuItem item = afmenu.FindMenuItem((AFMenu.MenuCommand)kMenuCommandProprietary);

                                           

                                          105                if (item != null) return;

                                           

                                          106

                                           

                                          107                // First add a separator.

                                           

                                          108                afmenu.AddSeparator();

                                           

                                          109                // Create a menu item.

                                           

                                          110                ToolStripMenuItem test = new ToolStripMenuItem("&Proprietary");

                                           

                                          111                test.MergeIndex = kMenuCommandProprietary;

                                           

                                          112                // Then the menu item.

                                           

                                          113                afmenu.Items.Add(test);

                                           

                                          114            }

                                           

                                          115        }

                                           

                                          116

                                           

                                          117        // Event raised when the menu is opened.

                                           

                                          118        void afmenu_Opened(object sender, EventArgs e)

                                           

                                          119        {

                                           

                                          120            // Get the AF menu.

                                           

                                          121            AFMenu afmenu = sender as AFMenu;

                                           

                                          122            if (afmenu != null)

                                           

                                          123            {

                                           

                                          124                // Iterate through the menu to show the tool strip menu items.

                                           

                                          125                System.Diagnostics.Debug.WriteLine("  List of items in menu:");

                                           

                                          126                for (int ii = 0; ii < afmenu.Items.Count; ii++)

                                           

                                          127                {

                                           

                                          128                    ToolStripMenuItem item = afmenu.Items[ii] as ToolStripMenuItem;

                                           

                                          129                    if (item == null) continue;

                                           

                                          130

                                           

                                          131                    // Use the text from the menu item directly.

                                           

                                          132                    System.Diagnostics.Debug.WriteLine("      menuText = " + item.Text);

                                           

                                          133                }

                                           

                                          134            }

                                           

                                          135        }

                                           

                                          136

                                           

                                          137        void afTreeView_MenuItemClicked(object sender, MenuItemClickedEventArgs e)

                                           

                                          138        {

                                           

                                          139            // Get the AF menu from the AF tree view.

                                           

                                          140            AFMenu afmenu = afTreeView.ContextMenuStrip as AFMenu;

                                           

                                          141            if (afmenu == null) return;

                                           

                                          142

                                           

                                          143            try

                                           

                                          144            {

                                           

                                          145                // Override the properties selection and display the dialog as read-only.

                                           

                                          146                if ((AFMenu.MenuCommand)e.ClickedItem.MergeIndex == AFMenu.MenuCommand.Properties)

                                           

                                          147                {

                                           

                                          148                    // Display the wait cursor.

                                           

                                          149                    this.Cursor = Cursors.WaitCursor;

                                           

                                          150

                                           

                                          151                    // Indicate to the caller that this click is handled.

                                           

                                          152                    e.Handled = true;

                                           

                                          153

                                           

                                          154                    // Show the properties read-only using the AFOperations method.

                                           

                                          155                    bool readOnly = true;

                                           

                                          156                    AFOperations.ShowProperties(this, afmenu.AFObject, afmenu.AFContext, afmenu.AFPath, afmenu.AFFilter, readOnly);

                                           

                                          157                }

                                           

                                          158                else if (e.ClickedItem.MergeIndex == kMenuCommandProprietary)

                                           

                                          159                {

                                           

                                          160                    // Display the wait cursor.

                                           

                                          161                    this.Cursor = Cursors.WaitCursor;

                                           

                                          162

                                           

                                          163                    // Indicate to the caller that this click is handled.

                                           

                                          164                    e.Handled = true;

                                           

                                          165

                                           

                                          166                    MessageBox.Show(this, "This is a proprietary menu item selection", "My menu item");

                                           

                                          167                }

                                           

                                          168            }

                                           

                                          169            finally

                                           

                                          170            {

                                           

                                          171                // Restore the default cursor.

                                           

                                          172                this.Cursor = Cursors.Default;

                                           

                                          173            }

                                           

                                          174        }

                                           

                                          175    }

                                           

                                          176}