C# Tutorial


The code in this example builds a .NET Windows form based application called CSharpSnapshot that returns a snapshot value for a PIPoint. It supports the PISDKDlg Tag Search control to find the point. It is written in C# in VisualStudio.NET

Here is what the finished application looks like:

  1. Step 1

Open VisualStudio.NET and select New>Project from the File menu. Select Visual C# Projects from the list of Project Types. Select Windows Applications from the list of Templates. Give it a name of CSharpSnapshot. Make sure the file location show is the desired location for your source files and click [OK].

  1. Step 2

After the wizard finishes, a blank form will be displayed. Change the Text parameter of the form to "Snapshot Value", by using the Properties window. This changes the Title Bar of the form to "Snapshot Value."

  1. Step 3

  2. Select the Label tool from the Toolbox. Click and drag the cursor to define a label near the top left of the form (see picture below). Enter "Server:" for the Text of this Label.
  3. Select the TextBox tool from the Toolbox. To the right of the label, click and drag the cursor to define a text box. Enter "localhost" for the Text of this TextBox. This TextBox should have a name of textBox1.
  4. Select the Label tool from the Toolbox. Click and drag the cursor to define a label below the "Server" label. Enter "Tagname:" for the Text of this Label.
  5. Select the TextBox tool from the Toolbox. To the right of the label, click and drag the cursor to define a text box. Enter "sinusoid" for the Text of this TexBox. This TextBox should have a name of textBox2.
  6. Select the Label tool from the Toolbox. Click and drag the cursor to define a label below the "Tagname" label. Enter "Timestamp:" for the Text of this Label.
  7. Select the TextBox tool from the Toolbox. To the right of the label, click and drag the cursor to define a text box. Make sure the Text of this TexBox is blank. Change the ReadOnly property to True. This TextBox should have a name of textBox3.
  8. Select the Label tool from the Toolbox. Click and drag the cursor to define a label below the "Timestamp" label. Enter "Value:" for the Text of this Label.
  9. Select the TextBox tool from the Toolbox. To the right of the label, click and drag the cursor to define a text box. Make sure the Text of this TexBox is blank. Change the ReadOnly property to True. This TextBox should have a name of textBox4.
  10. Select the Button tool from the Toolbox. Click and drag the cursor to define a button below the "Value" label. Enter "Tag Search:" for the Text of this Button.. This Button should have a name of button1.
  11. Select the Button tool from the Toolbox. Click and drag the cursor to define a button to the right of the "Tag Search" Button. Enter "Get Value" for the Text of this Button. This Button should have a name of button2.
  12. Step 4

Select Add Reference from the Project menu. Select the following references from the .NET tab:

OSIsoft.PISDK

OSIsoft.PISDKCommon

OSIsoft.PISDKCtl

OSIsoft.PISDKDlg

OSIsoft.PITimeServer

If you don't see these references, please refer to the section in this manual titled Using the PI-SDK with Microsoft Dot Net (chapter on Advanced Topics), for how to add these Interop Libraries to the Global Assembly Cache.

When you get all done, your project should look something like this:

  1. Step 5

Double click on the form. This will bring up the code window with the cursor positioned within the function Form1_Load.

Before you enter any code in this function, you need to add a global variable for the PISDK object and another for the Application object used by the SDK Dialogs. The PISDK object caches connections to PI Servers. You should create this once in your program and use it whenever you need it. The PI-SDK Dialogs Application object is used to display the Tag Search dialog.

Up near the top of the file, the class for the form is declared. After the opening brace ({) of the class, add a global variable for the PI-SDK object and the PI-SDK Dialog Application object.

public class Form1 : System.Windows.Forms.Form
	{
//
// Global Data
//
      PISDK.PISDK g_SDK;
      PISDKDlg.ApplicationObject g_SDKDlgAppObject;   // PISDK dialog app. object

Return to the Form1_Load function and enter the following code:

      private void Form1_Load(object sender, System.EventArgs e)
      {
//
// Create the SDK object here. That will give the program the 
//    benefits of caching of servers and points.
// Also create the PISDK Dialogs Application object so we can use
//    Tag Search.
//
         try {
            g_SDK = new PISDK.PISDKClass();
            g_SDKDlgAppObject = new PISDKDlg.ApplicationObjectClass();
         }catch (System.Runtime.InteropServices.COMException comExc){
            MessageBox.Show(comExc.Message,comExc.ErrorCode + " Error",
                            MessageBoxButtons.OK,
                            MessageBoxIcon.Exclamation);
         };
      }

  1. Step 6

Return to window showing the form and double click on the Button labeled "Tag Search". This will bring up the code window with the cursor positioned within the function button1_Click. Enter the following code:

      private void button1_Click(object sender, System.EventArgs e) {
//
// Display the Tag Search dialog and fill out the form with the result
//
      PISDKDlg.TagSearch myTagSearch;        // PISDK Tag search display object
      PISDK._PointList myPointList;         // point list returned from tag search
      PISDKCommon.NamedValues nvsSelServers; // Namedvalues collection of servers
      PISDKDlg.TagSearchOptions tsOptions;   // tag search dialog options
      object valInx;                         // Variant for index
      object strObject;                      // Variant for string

      myTagSearch = g_SDKDlgAppObject.TagSearch;
//
// Pass the server that is in textBox1 as a default.
// Only allow a single tag to be selected.
//
      nvsSelServers = new PISDKCommon.NamedValuesClass();
      strObject = textBox1.Text;
      nvsSelServers.Add(textBox1.Text,ref strObject);
      tsOptions = PISDKDlg.TagSearchOptions.tsoptSingleSelect;
      myPointList = myTagSearch.Show(nvsSelServers,tsOptions);
      if (0 != myPointList.Count) {
         valInx = 1;
//
// Get Server name
//
         textBox1.Text = myPointList.get_Item(ref valInx).Parent.Name;
//
// Get Tag name
//
         textBox2.Text = myPointList.get_Item(ref valInx).Name;
      };
      }

The declarations define each PISDK COM object you need in this function as well as a couple of temporary variables (valInx and strObject) you need to pass VARIANTS to COM methods.

      PISDKDlg.TagSearch myTagSearch;        // PISDK Tag search display object
      PISDK._PointList myPointList;         // point list returned from tag search
      PISDKCommon.NamedValues nvsSelServers; // Namedvalues collection of servers
      PISDKDlg.TagSearchOptions tsOptions;   // tag search dialog options
      object valInx;                         // Variant for index
      object strObject;                      // Variant for string

First the Tag Search Dialog object (myTagSearch) is created from the PISDK Dialogs Application object created in the Form1_Load method.

myTagSearch = g_SDKDlgAppObject.TagSearch;

Next a NamedValues collection is created to pass in the Server name in textBox1. This will be used as the default Server in the Tag Search dialog.

nvsSelServers = new PISDKCommon.NamedValuesClass();

The Add method of a NamedValues collection requires a pointer to a VARIANT for the value of the NamedValue being added. In .NET this must be passed as a reference to an object. The name of the Server is assigned to the strObject variable and then the Server is added to the NamedValues collection (nvsSelServers).

strObject = textBox1.Text;

nvsSelServers.Add(textBox1.Text,ref strObject);

The Tag Search options are set to restrict the number of tags returned to one.

tsOptions = PISDKDlg.TagSearchOptions.tsoptSingleSelect;

Finally, the Tag Search dialog is displayed.

myPointList = myTagSearch.Show(nvsSelServers,tsOptions);

The Tag Search dialog returns a PointList. Next the list is checked to see if it has a tag in it. If so, the Server name is written to textBox1 and the tag name is written to textBox2.

if (0 != myPointList.Count) {

valInx = 1;

//

// Get Server name

//

textBox1.Text = myPointList.get_Item(ref valInx).Parent.Name;

//

// Get Tag name

//

textBox2.Text = myPointList.get_Item(ref valInx).Name;

};

  1. Step 7

Return to the window showing the form and double click on the Button labeled "Get Value". This will bring up the code window with the cursor positioned within the function button2_Click. Enter the following code:

      private void button2_Click(object sender, System.EventArgs e) {
//
//  Get the snapshot value of the tag in textBox2 from the server
//    in textBox1
//
      PISDK.Server myServer;     // server object from the name in textBox1
      PISDK.PIPoints myPoints;   // PIPoints collection of server
      PISDK.PIPoint snapPoint;   // point from the name in textBox2
      PISDK.PIValue myValue;     // snapshot value
   
      if (textBox1.Text.Equals("")) {
         MessageBox.Show("No server entered.","Error",MessageBoxButtons.OK,
            MessageBoxIcon.Exclamation);
      }else{
         if (textBox2.Text.Equals("")) {
            MessageBox.Show("No tag entered.","Error",MessageBoxButtons.OK,
               MessageBoxIcon.Exclamation);
         }else{
            try {
               myServer = g_SDK.Servers[textBox1.Text];
               myPoints = myServer.PIPoints;
               snapPoint = myPoints[textBox2.Text];
               myValue = snapPoint.Data.Snapshot;
               textBox3.Text = myValue.TimeStamp.LocalDate.ToString();
//
// Check to see if we got a digital state back
//
               if (myValue.Value.GetType().IsCOMObject) {
                  PISDK.DigitalState myDigState;
                  myDigState = (PISDK.DigitalState) myValue.Value;
                  textBox4.Text = myDigState.Name;
               }else{
                  textBox4.Text = myValue.Value.ToString();
               };
            }catch (System.Runtime.InteropServices.COMException comExc) {
               MessageBox.Show(comExc.Message,comExc.ErrorCode + " Error",
                  MessageBoxButtons.OK,MessageBoxIcon.Exclamation);
            };
         };
      };
      }

The declarations define each PISDK COM object we need in this function.

PISDK.Server myServer; // server object from the name in textBox1

PISDK.PIPoints myPoints; // PIPoints collection of server

PISDK.PIPoint snapPoint; // point from the name in textBox2

PISDK.PIValue myValue; // snapshot value

The first thing the function does is check for a blank Server or Tagname, displaying an error dialog and then exiting the function.

if (textBox1.Text.Equals("")) {

MessageBox.Show("No server entered.","Error",MessageBoxButtons.OK,

MessageBoxIcon.Exclamation);

}else{

if (textBox2.Text.Equals("")) {

MessageBox.Show("No tag entered.","Error",MessageBoxButtons.OK,

MessageBoxIcon.Exclamation);

Next, a try/catch block is entered so any errors thrown by the SDK calls can be caught, and a dialog box with the error displayed.

try {

...

}catch (System.Runtime.InteropServices.COMException comExc) {

MessageBox.Show(comExc.Message,comExc.ErrorCode + " Error",

MessageBoxButtons.OK,MessageBoxIcon.Exclamation);

};

Within the try portion of the block, the Server specified in textBox1 is retrieved from the Servers collection of the PISDK object.

myServer = g_SDK.Servers[textBox1.Text];

Then the PIPoints collection of that Server is obtained.

myPoints = myServer.PIPoints;

Next, the PIPoint specified in textBox2 is retrieved from the PIPoints collection.

snapPoint = myPoints[textBox2.Text];

Next, the snapshot value of the PIPoint is retrieved from the Server.

myValue = snapPoint.Data.Snapshot;

The time stamp of the PIValue is written to textBox3.

textBox3.Text = myValue.TimeStamp.LocalDate.ToString();

The Value may be a number or a DigitalState SDK object, so that is checked for next.

if (myValue.Value.GetType().IsCOMObject) {

If it is a digital state, the Value is cast to a DigitalState and the value written to textBox4.

PISDK.DigitalState myDigState;

myDigState = (PISDK.DigitalState) myValue.Value;

textBox4.Text = myDigState.Name;

If it is not a DigitalState, the Value is written to textBox4 as a number.

textBox4.Text = myValue.Value.ToString();

  1. Step 8

The project is complete. Save it and test the application.

Enabling Operational Intelligence