Skip navigation
All Places > PI Developers Club > Blog > 2009 > December
2009

This is just a quick note to let you know I'll be leaving for the Holidays shortly, returning on January 4th. And I wanted to take this opportunity to send all of you my best wishes for the Holiday season! I'm confident you won't even notice I'm gone, with Andreas, Cristobal and Han Yong taking care of you

 

I know we repeated this a lot lately (on the forums and blogs, at the OSIsoft vCampus Live! event), but just one more time as we approach the end of the year: thank you so much for making 2009 so successful for vCampus! Thanks for believing in this new program, thanks for having faith in us as your connection to the whole OSIsoft ecosystem, and thanks for being an active part of the community. I look forward to strengthening this relationship with you all in 2010, bringing always more value to all of you, customers, partners and colleagues at OSIsoft.

 

Merry Christmas, Happy New Year!, and see you in 2010!

I was a little perplexed by the large amount of food donated to Special 'E' by event at the Palace Hotel.  Specail 'E' is the organization that collects "extra" food for the homeless in the Bay Area with whom we arranged a donation.  As it turns out the Palance liked the idea, so they were donating ALL the "extra" food from the entire week for ALL venues to Special 'E'!  At the end of a long week the Palace donated over 500 pounds ( 226 Kg) to the program.  I suspect and hope they will continue this effort.  Some experts estimate that 96 Billion pounds of editable food each year is thrown out.  I was glad we could do our part however small.

 

 

For those of you who know me, hopefully you can get an understanding of  how excited I am with this Event Frame CTP announcement.  I am generally an excitable person, but I really get excited when discussing Event Correlation Analysis and that's exactly what Event Frames is meant to enable within the PI System.  There have already been some questions on what we are trying to accomplish with Event Frames, I'd like to shamelessly plagiarize from my good buddy Chris Coen who is much better at speaking (and writing) English than myself:

 

 

 

"Event Frames allow you to name, store, organize, search and analyze important time periods.  That way you can study the real-time and external data that happened during or led up to these events without needing to first look up the time ranges.  PI does that for you.  It's like a way of indexing the supporting real-time data so you can look it up in terms of your business rather than by trying to remember the time periods when they occurred." 

 

 

 

First we need to have a level setting discussion; i.e. is this production ready code?  This CTP is a great milestone for the Event Frames Initiative and I don't want to understate its importance; but there is still a lot of development work that needs to be completed before there is a production release of  Event Frames worthy of the OSIsoft name.  This will be the subject of future posts!

 

 

 

The Event Frames team has dedicated the past three years working with numerous customers and partners to feed product requirements, use cases, and user scenarios.  We've used this information to create this initial CTP and we would like to politely focus your attention in two areas 1) General Event Frame Functionality and 2)  Object Model Data Access.  We are working on a lot of other areas, but these two are the main focus of this CTP.

 

 

 

The first thing you will need to accomplish is creating Event Frames.  In order to get your creative juices flowing, I've created a simple Event Frame Simulator Application.  I will be demonstrating this simulator during the Event Frames webinar; but I wanted to share the code in order for you to get a jump start on using Event Frames.  We also used this simulator for the Event Frames Learning Lab at the OSIsoft vCampus Live! 2009 event(Which by the way was a fantastic event.  I've been to every OSI conference or event since 1997, except for 2 because of my wedding and my daughter's birth and this was one of the best I've ever attended) .

 

 

 

The Event Frames Simulator will create Downtime Event Frames on Elements based on a chosen Element/Event Frame Template and/or Element Category.  Although the simulator is initially focused on downtimes; I have made it flexible so you can use other Templates in order to experiment with the functionality.  The Simulator can be found here.  

 

 

 

Important to note that the primary User Interface for this CTP is PI System Explorer.  Event Frames functionality is fully documented within AF 2.1 User Manuals and Help files.

 

 

 

That's all I have for now.  I invite you to experiment with Event Frames in AF 2.1 and please provide us with your feedback on the Event Frames Development discussion forum.  We will be checking it!

 

 

 

PS - If I may ask; okay I will - The Event Frames team is extremely interested in hearing your ideas on User Experience!!  As I said in the beginning; I'm a big proponent of Event Correlation Analysis and Event Frames enable this by providing the time duration.  I'm really interested to hear ideas from our customers and partners.  Maybe that's a good idea for a discussion post, HINT, HINT!!!!

Those who were at the OSIsoft vCampus Live! 2009 event might remember that Matt Miller listed a number of charitable actions derived from the event, in the closing session. One of those was the possibility for attendees to donate their giveaway OSIsoft jacket to Institute on Aging, an organization that helps senior of the San Francisco area live independently. As a result, 21 jackets were donated by our generous attendees. We'd like to share a note we received from the Institute upon receiving the donations:

 

Just wanted to let you both know that the Institute on Aging was really happy to receive the OSIsoft coats.  The timing is perfect because they are in the midst of a huge coat drive for bay area seniors and the SF poor.  The OSIsoft fleeces are perfect for the SF weather (especially this week).   Rudy at the IOA said it’s one of the best gifts you can give – warmth.

 

Thank you!

The first OSIsoft vCampus Live! event is over, it was a huge success. Thanks to all of you who could join us, making this experience so memorable.

 

There was a lot to do, enough fantastic food and information for a week (maybe two). We heard most of you really got a lot of great information out of it (which created 18 new vCampus subscribers in 2 days!).

 

vCampus.jpg

 

We all had the chance to talk to the developers and product managers on most OSIsoft products, including AF, PI Server, PI Notifications, AF SDK and PI SDK and had a in-depth look at the new products and features. Which, in retrospect was a long list!

 

This year we introduced a few new concepts for the event, such as the Technology Roundtables and 2 Extreme Code Review sessions - one was the Element Relative Display (ERD) add-in presented by the PI ProcessBook team and the other one was Micheal van der Veeken’s personal project LinqToPI. Thanks for sharing the code. The feedback was very positive, and we'll look to include them again next year.

 

A sizable group of attendees stayed with us for the third day and participated in the Hands-On Learning Labs, which feature more than 40 different exercises to choose from, a free USB with the documentation, help from many qualified people and the chance to take the printed book with you if you felt it was not too big.  I counted 17 new labs this year with an impressive range of topics.  I will look forward to hearing the feedback on those.

 

News announcements made on the event include the Event Frames CTP (which is available now in OSIsoft vCampus - see here), the StreamInsight CTP (within the next few weeks) as well as details on the next Users Conference (see here). We hope to see you there!

 

Another exciting announcement was the "OSIsoft vCampus All-Star" program - similar to Microsoft MVP, we will be recognizing our best contributors in the community. The nominees will be announced at OSIsoft vCampus Live! 2010 and will benefit from the following.

  • Personal blog
  • Forum moderator privileges
  • Free admission to the OSIsoft Users Conference and OSIsoft vCampus Live! Events in the next year.
  • Option to take part in the OSIsoft vCampus Team weekly meetings
  • Free 1-year subscription or renewal to OSIsoft vCampus

So, we invite all of you to actively participate in the community. Share your knowledge and give your feedback.  Like all communities if everyone adds a little bit, the whole community becomes enriched.

 

Along the way our event managed to give a little back to the community too!  The food we didn't get a chance to eat, was donated to Special E who made sure it found it's way to local shelters, along with repurposing our signage and conference materials.  Twenty-one attendees donated thier new jacket to the Institude on Aging which helps diabled adults and seniors with independant living.  Thank-you for that! And lastly, we upgraded our dinner wine to include LookOut Ridge Library Cabernet, which was very popular at Wednesday's Keynote Dinner.  That was a good thing, becuase 7 wheelchairs were donated to the Wheelchair Foundation to help those in need world-wide through that investment.

 

By the way, this year (if you were not here) you missed out on quite a few interesting presentations like: “Connecting Custom Web Parts to OSIsoft PI Web Parts”, “Hacking your way to more secure code”, “Programming with Event Frames”, “1001 uses for PI Web Services”, “Metadata Replication in AF”, “Architecture and Deployment concerns” and the closing note “OSIsoft and Microsoft: Future Direction”.  I especially liked the session on PI integration with Surface, but then again, I am a geek!

 

Work has already started for next years event.  We have lots of great ideas and are poring though all of your feedback.  Once we get a handle on all of that we'll post the details for next years dates.

 

Thank-you all for making it a great experience!  Hope to see you again next year!

 

 

Note

The official version of this document available in the vCampus Library check under White Papers and Tutorials, PI WebParts. Feedback on either the official version or this blog post is welcome and appreciated. This blog post will be updated soon to reflect all the changes included in the vCampus Library version. Happy Coding! .- Kryz

Introduction

Using SharePoint Services is really fulfilling when you are doing simple things, but to really use it at all its possibilities you would need to get additional Web Parts, either created by someone else (like OSIsoft's RtWebParts) or creating one Web Part yourself. OSIsoft provides a great range of Web Parts that allows the end user to do a great deal of things, but there is always one specific need that is not shared and that does not fit with what we currently have at our disposal, is in this case where we need to connect to (or from) a different data source to the PI Server data and integrate all of this in a seamless/Client&Server/web interface.

Overview

In order to integrate all of this into Sharepoint you will need to create a Custom Web Part that connects with OSIsoft's RtWebParts and understand a little bit of the fundamental parts of an RtWebpart, this will not be an easy path, but I'm sure you'll find a great guide in this tutorial.

The Contents of a Web Part Page

A WebParts Page has zones, and each zone may have WebParts, the webparts interact with each other sending and receiving values, parameters, row values, etc. Some webparts can even send parameters across diferent WebPart Pages.

 

Web-Parts-Example.png 

Reference

We will be using a modified version of this step by step tutorial, the main reason for this is that it somewhat does what we need, but in order to make it really compatible we need to make a few changes that are depicted in full detail here. Please keep this in mind as there will be some steps that won't be needed here.

Pre-requisites

  • Visual Studio 2008 and at least the Service Pack 2
  • Windows Server 2003 or  2008 (or any other version that supports SharePoint Services)
  • Visual Studio Extensions for SharePoint Services 1.3 or later.
  • SQL Server [Express] 2005 or 2008 with latest service pack
  • OSIsoft's RtWebParts installed on the SharePoint Server
  • PI Server in the same network (or in the same computer, note that having the server in the same computer is not recommended for a production enviroment)

Creating a base Web Part

  • I will be using Visual Studio 2008 with Extensions for SharePoint Services 1.3, this is how the splash screen for my visual studio 2008 looks in my computer.
    000-_2D00_-Splash.jpg

  • I created a new project using the new project menu as illustrated in the following picture
    001-_2D00_-New-Project.png

  • Navigate to Visual C#, locate SharePoint, and select WebPart
    002-_2D00_-New-Project-10262009-124332-PM.bmp.jpg

  • When you get asked to select trust level please select Full trust (Deploy to GAC) and click Ok. (this will only appear if you have Service Pack 2 installed in Visual Studio 2008)
    003-_2D00_-Select-Trust-Level-10262009-124343-PM.bmp.jpg

  • You will be greeted with a default WebPart already created, your screen should look a lot like this:
    004-_2D00_-First-Screen.png
  • I selected the WebPart1.cs and renamed it to 'Tut_WP_OSI.cs', when you get asked if you want to rename all associated Web Parts, click YES. (this will only appear if you have Service Pack 2 installed in Visual Studio 2008)
    005-_2D00_-Rename-Web-Part-10262009-11250-PM.bmp.jpg

  • I changed the base class from System.Web.UI.WebControls.WebParts.WebPart to the Microsoft.SharePoint.WebPartsPages.WebPart (which is a little bit older, but compatible with OSIsoft WebParts) doing the following code:

    //Change it from this ...
    public classTut_WP_OSI : System.Web.UI.WebControls.WebParts.WebPart

    //... to this
    public classTut_WP_OSI : Microsoft.SharePoint.WebPartPages.WebPart

    I also uncommented the provided 'Hello world' code and compiled it. Please note that it will say that our base class is not CLS-compliant. I sincerely do not know what this means (evil grin)

    //Uncomment those lines:
    Label label = new Label();
    label.Text = "Hello World";
    this.Controls.Add(label);

    010-_2D00_-Build-01.png

  • Testing the base WebPart

  • For the fun part, go to your sharepoint site and navigate to the Document Center, mine is conveniently located at localhost
    011-_2D00_-Document-center.png

  • Under Site Actions select Create as illustrated in the next picture
    012-_2D00_-Create-page-00.png

  • Under Web Pages select Web Part Page
    013-_2D00_-Web-Part-Page-00.png

  • I named the WebPage tut_webpart_conn.aspx and selected Header, Footer, 3 Columns then clicked create
    014-_2D00_-tut_5F00_webpart_5F00_conn.png

  • I wanted to add the recently compiled webpart to the Left Column
    015-_2D00_-Add-webpart-01.png

  • I found the WebPart under Miscellaneous as expected.
    016-_2D00_-Fullscreen-capture-10262009-13125-PM.bmp.jpg

  • Everything seems to work fine in edit mode. and I sincerely believe it to be better to build upon a working webpart than walking blindfolded.
    017-_2D00_-WebPart-working.png

  • I was kindly greeted by the 'Hello world' comment, that means that everything is working in run mode too.
    018-_2D00_-Exit-edit-mode-00.png

  • Making the WebPart Connectable

    (Note that the steps on this section correspond to the ones in this web page)
  • Step 1: Create the Interface Class This is achieved by adding the interface IParametersOutProvider to the base clase

    //add this to the 'using' definitions
    using Microsoft.Sharepoint.WebPartPages.Communication;

    //Change it from this ...
    public classTut_WP_OSI : Microsoft.SharePoint.WebPartsPages.WebPart

    //... to this
    public classTut_WP_OSI : Microsoft.SharePoint.WebPartsPages.WebPart,
      IParametersOutProvider//step 1


  • Step 2: Declare Events We need to add the events that this WebPart will handle and we need to include the WebPartPages.Communication namespace as follows:

    //add this to the WebPart Class
    public event NoParametersOutEventHandler NoParametersOut;
    public event ParametersOutProviderInitEventHandler ParametersOutProviderInit;
    public event ParametersOutReadyEventHandler ParametersOutReady;

    Those are the events that are expected by this interface (and by the client side scripting later on).
    019-_2D00_-Step-1-n-2.png

  • Step 3: Override the EnsureInterfaces method, and then call the RegisterInterace method
    We need to register the interface we want to expose to other webparts.

    //Add this to our WebPart class
    [Obsolete]
    public override void EnsureInterfaces()
    {
      RegisterInterface("TagListProvider_WPQ_", InterfaceTypes.IParametersOutProvider,
                        UnlimitedConnections, CanRunAt(), this, "TagListProvider_WPQ_",
                        "Provide a list item to", "Provides a list item to a connected webpart");
    }

    It is important to pass the first parameter just as it is, we need the '_WPQ_' or SharePoint will refuse to load it as it won't have a unique name. also it has to be the same name the client side scripting has or it won't get called.
    020-_2D00_-Step-3.png

  • Step 4: Override the CanRunAt Method

    //Add this to our WebPart class
    [Obsolete]
    public override ConnectionRunAt CanRunAt()
    {
      return ConnectionRunAt.Server;
    }

    021-_2D00_-Step-4.png

  • Step 5: Override the PartCommunicationConnect method

    //Add this to our WebPart class
    private bool paramsOutConnected = false;

    [Obsolete]
    public override void PartCommunicationConnect(
      string interfaceName, Microsoft.SharePoint.WebPartPages.WebPart connectedPart,
      string connectedInterfaceName, ConnectionRunAt runAt)
    {
      paramsOutConnected = true;
    }

    This tells the SharePoint Server that we need a full refresh to show the information (a fact that we will change later with client side scripting)
    022-_2D00_-Step-5.png

  • Step 6: Override the PartCommunicationInit method

    //Add this to our WebPart class
    [Obsolete]
    public override void PartCommunicationInit()
    {
      ParametersOutProviderInitEventArgs parametersOutProviderInitEventArgs =
        newParametersOutProviderInitEventArgs();
      parametersOutProviderInitEventArgs.ParameterOutProperties = newParameterOutProperty[1];
      parametersOutProviderInitEventArgs.ParameterOutProperties[0] = newParameterOutProperty();
      parametersOutProviderInitEventArgs.ParameterOutProperties[0].ParameterName =
        "TagName";
      parametersOutProviderInitEventArgs.ParameterOutProperties[0].ParameterDisplayName =
        "Selected Tag";
      parametersOutProviderInitEventArgs.ParameterOutProperties[0].Description =
        "The selected tag name";
      ParametersOutProviderInit(this, parametersOutProviderInitEventArgs);
    }

    I hate telling you a bounch of "do nots" but be really sure that this section matches the text you put on the client side JavaScript file, because if it is different by any bit it won't get called even if it is on the webpage.
    023-_2D00_-Step-6.png

  • Step 7:  Override the PartCommunicationMain method

    //step 7
    private DropDownList dropDownList;

    [Obsolete]
    public override void PartCommunicationMain()
    {
      EnsureChildControls();
      ParametersOutReadyEventArgs parametersOutReadyEventArgs = newParametersOutReadyEventArgs();
      parametersOutReadyEventArgs.ParameterValues = new string[1];
      parametersOutReadyEventArgs.ParameterValues[0] = dropDownList.SelectedValue;
      ParametersOutReady(this, parametersOutReadyEventArgs);
    }

    024-_2D00_-Step-7.png

  • Step 8: Override the GetInitEventArgs method
    There is no need to override the GetInitEventArgs method as we will not be providing conversion mechanisms to connect to different types of webparts.
  • Step 9:Implement the interface event handlers
    The interface we are using has no must-implement event handlers, so we can skip this step as well.
  • Step 10: Override the RenderWebPart method

    //Step 10
    protected override void RenderWebPart(HtmlTextWriter output)
    {
      EnsureChildControls();
      if (paramsOutConnected)
      {
        dropDownList.Attributes["onchange"] =
          "javascript:__doPostBack('" + this.UniqueID + "', '');";
      }
      base.RenderWebPart(output);
    }

    We need to tell the webpage to do a full page refresh.
    025-_2D00_-Step-8-n-9-n-10.png

  • Step 11: Implement supporting methods

    //Step 11
    using System.Web.UI.HtmlControls;

    string
    textData = "Sinusoid\r\nCDT158\r\nSinusoidU";

    protected override void CreateChildControls()
    {
        base.CreateChildControls();

        HtmlTable htmlTable = newHtmlTable();
        HtmlTableRow tr = newHtmlTableRow();
        htmlTable.Rows.Add(tr);
        HtmlTableCell tc = newHtmlTableCell();
        tr.Cells.Add(tc);
        Label titleLabel = newLabel();
        titleLabel.Font.Bold = true;
        titleLabel.Text = "Value";
        tc.Controls.Add(titleLabel);
        tc = newHtmlTableCell();
        tr.Cells.Add(tc);

        dropDownList = new DropDownList();
        dropDownList.Items.Clear();

        string[] arrText =
          textData.Split(new string[1] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
        for (int i = 0; i < arrText.Length; i++)
        {
            dropDownList.Items.Add(newListItem((string)arrText[ i ],
                                                (string)arrText[ i ]));
        }
        tc.Controls.Add(dropDownList);
        Controls.Add(htmlTable);
    }

    Here we define the controls we want to see when the webpart is rendered, we could even hide that if the webpart is not connected. But for the time being we will just use that as it is.
    026-_2D00_-Step-11.png

  • Testing the Connectable WebPart

  • Once again I do prefer to see it live and kicking, so here I went back to the website to see if the changes we have made so far are working correctly, and I can see the dropdown and the content just fine. We are on the right track.
    027-_2D00_-Working-02.png

  • I would like to see if we can connect this webpart to another webpart (an OSIsoft one) so I'll be adding a RtTrend for the sake of testing. Under Site actions click on EditPage
    028-_2D00_-Edit-02.png

  • Click on the center webpart zone that reads Add a webpart
    029-_2D00_-Add-WebPart-02.png

  • Look for and select RtTrend then click the button Add
    030-_2D00_-Fullscreen-capture-10262009-25418-PM.bmp.jpg

  • Back on the newly added webpart click under Edit go to Connections select Receive parameter values from... and finally click on the Tut_WP_OSI Web Part
    031-_2D00_-Connections-01.png

  • Now that it is connected, we need to select were we want to use the parameter that comes in, so we select edit from the RtTrend Web Part and then click on Modify Shared Web Part
    032-_2D00_-Modify-02.png

  • Look for the Selected Data section in the RtTrend Property pane and click on the ligthning bolt
    033-_2D00_-Connections-02.png

  • You'll be presented with another window that has all the Web Parts that are connected to this one and, after selecting a webpart, all the connection fields (parameters) that it is exposing. Click on Tut_WP_OSIWebPart and then on Value close the window by pressing the Ok button
    034-_2D00_-Fullscreen-capture-10262009-25726-PM.bmp.jpg

  • Close the property pane by pressing the OK button
    035-_2D00_-Ok-02.png

  • It is working, at least for the first parameter!
    036-_2D00_-Exit-edit-mode-02.png

  • Clicking on the second one shows the second tag, after that I clicked on the dropdown again just to show it off.
    037-_2D00_-Running-OK-01.png

  • Adding a property and making the WebPart web editable

  • Since we would not want our webpart to have the same taglist all the time and sure it would be nice to let the end-user select the tags they want to display, then we will make this webpart web editable.
    Step 12: Add the IWebEditable interface and the property

    //Modify the class interfaces by adding IWebEditable
    public classTut_WP_OSI : Microsoft.Sharepoint.WebPartsPages.WebPart,
      IParametersOutProvider//step 1

    //... like this
    public classTut_WP_OSI : Microsoft.Sharepoint.WebPartsPages.WebPart,
      IParametersOutProvider, IWebEditable//step 1, 12

    //Move the textData definition up and change it to
    private string textData = string.Empty;

    //add this to the 'using' definitions
    using System.ComponentModel;

    [WebDisplayName("Text Data"),Category("Configuration"),
    WebBrowsable(false),WebPartStorage(Storage.Personal)]

    public string TextData
    {
      get { return textData; }
      set { textData = value; }
    }

    object IWebEditable.WebBrowsableObject
    {
      get { return this; }
    }

    038-_2D00_-Step-12.png

  • Step 13: Create the EditorPart based class

    class Tut_WP_OSI_Editor : EditorPart //step 13
    {
      private TextBox textData;
      public Tut_WP_OSI_Editor()
      {
        ID = "Tut_WP_OSI_Editor";
      }

      protected override void CreateChildControls()
      {
        base.CreateChildControls();
        Label label = new Label();
        label.Text = "Data";
        Controls.Add(label);
        Controls.Add(new HtmlGenericControl("br"));
        textData = new TextBox();
        textData.TextMode = TextBoxMode.MultiLine;
        textData.Rows = 5;
        textData.Wrap = false;
        textData.Width = 200;
        Controls.Add(textData);
        Controls.Add(new HtmlGenericControl("br"));
      }

      
    public override bool ApplyChanges()
      {
        Tut_WP_OSI listProvider = (Tut_WP_OSI)WebPartToEdit;
        listProvider.TextData = textData.Text;
        return true;
      }

      public override void SyncChanges()
      {
        EnsureChildControls();
        Tut_WP_OSI listProvider = (Tut_WP_OSI)WebPartToEdit;
      }
    }

    039-_2D00_-Step-13.png

  • Step 14: Create the CreateEditorParts() method 

    //add this to the 'using' definitions
    using System.Collections.Generic;

    //step 14
    EditorPartCollection IWebEditable.CreateEditorParts()
    {
      List<EditorPart> editorPartList = new List<EditorPart>();
      editorPartList.Add(new Tut_WP_OSI_Editor());
      return new EditorPartCollection(editorPartList);
    }

    This section returns the object needed when and while in edit mode.
    040-_2D00_-Step-14.png

  • Testing the WebPart's web editable property

  • That's it for adding a web editable property to a webpart. We can see it is still working at the webpart page.
    041-_2D00_-Testing-custom-property.png

  • How about testing it out, let's click on the arrow and then on Modify Shared Web Part
    042-_2D00_-Modifying-shared-webpart.png

  • This should bring us to the properties pane, and we should be able to see and edit the Data section and I've put "CDT158", "SINUSOID" and "SINUSOIDU", one per line. And then clicked on Ok
    043-_2D00_-Editing-the-tag-list-for-the-dropdown.png

  • We can see the Web Part working correctly.
    044-_2D00_-Verifying-the-functionality.png

  • We still need to test out if it can change the tag by clicking on the dropdown.
    045-_2D00_-Checking-drowdown.png

  • And now we have a Server Side connected WebPart!
    046-_2D00_-Done-with-server-side.png

  • Adding client side scripting

  • Add the JavaScript file to the project (note that you could have as easily added an existing item)
    047-_2D00_-Add-new-item.png
  • I will name this new item TagListProvider.cs and select it to be a JScript File
    048-_2D00_-TagListProvider.png
  • You can paste the following code, (just the yellow patches) you'll see some comments around them, mainly it is the client side code for the interfaces we have defined in the server side code.

    <SCRIPT LANGUAGE="JavaScript">
    <!--
    // TagListProvider object is the client-side implementation of the ParametersOutProvider interface
    function TagListProvider(wpq, dropDownListClientID, title) {
        this.WPQ = wpq;
        this.DropDownListClientID = dropDownListClientID;
        this.Title = title;

        // ParametersOutProvider interface
        this.RaiseParametersOut = _raiseParametersOut;
        this.PartCommunicationInit = _partCommunicationInit;
        this.PartCommunicationMain = _partCommunicationMain;
        this.ParametersOutReady = _parametersOutReady;
        this.NoParametersOut = _noParametersOut;

        // prepare parameters to be passed through the connection(s)
        function _raiseParametersOut()
        {
            var parametersOutReadyEventArgs = new Object();
            parametersOutReadyEventArgs.ParameterValues = new Array(1);
            var dropDownList = document.all(this.DropDownListClientID);
            var selectedValue = dropDownList.options[dropDownList.selectedIndex].value;
            parametersOutReadyEventArgs.ParameterValues[0] = selectedValue;
            this.ParametersOutReady(parametersOutReadyEventArgs);
        }

        // initialize connection information
        function _partCommunicationInit()
        {
            var parametersOutProviderInitEventArgs = new Object();
            parametersOutProviderInitEventArgs.ParameterOutProperties = new Array(1);
            parametersOutProviderInitEventArgs.ParameterOutProperties[0] = new Object();
            parametersOutProviderInitEventArgs.ParameterOutProperties[0].Description =
              "List of tags";
            parametersOutProviderInitEventArgs.ParameterOutProperties[0].ParameterDisplayName =
              "Tag List";
            parametersOutProviderInitEventArgs.ParameterOutProperties[0].ParameterName =
              "TagName";
            parametersOutProviderInitEventArgs.ParameterOutProperties[0].Required = false;
            WPSC.RaiseConnectionEvent("TagListProvider" + this.WPQ,
              "ParametersOutProviderInit", parametersOutProviderInitEventArgs);
        }

        // entry point for connection
        function _partCommunicationMain()
        {
            this.RaiseParametersOut();
        }

        // signals the connection infrastructure that new values are ready
        function _parametersOutReady(parametersOutReadyEventArgs) {
            WPSC.RaiseConnectionEvent("TagListProvider" + this.WPQ, "ParametersOutReady",
                                      parametersOutReadyEventArgs);
        }

        // special function for when there are no parameter values to pass
        function _noParametersOut()
        {
        }
    }
    -->
    </script>

    I know I wrote this before but: be sure, make really sure you use the same parameters here as in the previous section or those two objects (the client side and the server side) will not play well with each other.
    Someone commented that if you dare to remove the "title" variable from the JavaScript section it will break the ability to connect to other webparts. So please be aware of that if you try to compress or minimize the JavaScript code.
    049-_2D00_-JavaScript-source.png
  • Change its compilation action to embedded resource
    050-_2D00_-Embedded-Resource.png
  • Step 15: Modify the "CanRunAt" function

    //Add this to our WebPart class
    [Obsolete]
    public override ConnectionRunAt CanRunAt()
    {
      if (this.BrowserDesignMode) return ConnectionRunAt.Server;
      return ConnectionRunAt.Client;
    }

    We need to run in server mode while in edit but we want it to run in client mode while not in edit mode, so we use the 'if' for that.
    051-_2D00_-Step-15.png
  • Step 16: Modify the GetScript Method

    private string GetScript() {
      string JavaScript = string.Empty;

      // get a reference to the current assembly so we can get to the ResourceManager
      System.Reflection.Assembly thisAssembly =
        System.Reflection.Assembly.GetExecutingAssembly();

      // the name of the resource is dependent on the project's folder structure
      Stream scriptStream =
        thisAssembly.GetManifestResourceStream(
          this.GetType(), "Tut_WP_OSI.TagListProvider.js");

      using (StreamReader scriptReader = newStreamReader(scriptStream))
      {
        JavaScript = scriptReader.ReadToEnd();
      }

      return JavaScript;
    }

    This is the method Greg used to get the file from the assembly, and I liked that idea.
    052-_2D00_-Step-16.png
  • Step 17: Modify the OnPreRender Method

    //step 17
    protected override void OnPreRender(EventArgs e)
    {
      base.OnPreRender(e);
      if(paramsOutConnected)
      {
        if (CanRunAt() == ConnectionRunAt.Client)
        {
          dropDownList.Attributes["onchange"] =
            string.Format(
              "javascript:TagListProvider{0}.RaiseParametersOut();",
              ReplaceTokens("_WPQ_"));
          if (!Page.ClientScript.IsClientScriptBlockRegistered("ListProvider"))
            Page.ClientScript.RegisterClientScriptBlock(
              typeof(string), "ListProvider", GetScript());
          string initScript =
            @"var TagListProvider_WPQ_ = new TagListProvider('_WPQ_', '{0}', '{1}');";
          initScript = string.Format(
            ReplaceTokens(initScript), dropDownList.ClientID, this.StorageKey);
          Page.ClientScript.RegisterClientScriptBlock(
            typeof(string), ReplaceTokens("TagListProvider_WPQ_"), initScript, true);
        }
      }
    }

    We need to get the JavaScript client side script to the client, and this is the place to do it, it won't work on "WebPartPreRender" as it get's executed too late, so we need to override this section in order to inject the JavaScript code.
    053-_2D00_-Step-17.png
  • Testing client side scripting

  • This is best done on the webpage, so it is left as an excercise to our readers, do not forget to test it while the scroll position is down so you can see how the data changes without refresing the whole web page.
  • Try adding twice the webparts and verifying that they play well wich each other.

    Conclusions

  • Web Parts is a mature product and a really complex service from Microsoft, it is as complex as it is capable. So, be aware of what you are getting into.
  • The OSIsoft Provided Web Parts work almost flawlessly. That should take a lot of load out of our backs. And they integrate quice nicely, so use them as much as you want.
  • Tips

  • When creating a custom Web Part please do not forget the Shampoo's motto: Code, Test, Repeat.
  • For JavaScript loading save yourself a lot of headaches and override the PreRender method and use it for this.
  • All the connection information typed in the aspx source file must be identical to its JavaScript source part or the Web Part won't work.
  • To Do

  • The configuration does not get read from the storage after it was originally modified.

Today at OSIsoft's vCampus Live! conference we are announcing a milestone for our Event Frames initiative:  the release of the Community Technology Preview (CTP).

 

All the details of the CTP are in this document.

 

Event Frames is a new data type that is useful for storing events such as downtime, startups, environmental excursions, as well as batches.  In fact, any event with a start and an end time and other optional data (like the asset, or operator, or comment, or lot number) can take advantage of Event Frames for its storage.  Just like AF Elements provide context to the time-series data streams, Event Frames provides context to the actual time-series data.  For example, you can look up your last 5 equipment startups and use those times to see the associated time-series data.

 

This CTP milestone is our first release of Event Frames outside the walls of OSIsoft.  It provides the database, programmatic SDK, and management tools (PI System Explorer) for you to get started. See how you can use Event Frames in your applications.  As we progress to our next milestone, we'll post examples, thoughts and of course announcements here on this blog.

 

Have a question, a comment, a success story?  Please visit the Event Frames Development discussion forum and post it there.

 

We're looking forward to hearing your feedback!

 

 

Filter Blog

By date: By tag: