Pie Chart#1:Using the WPF element combined with additional assemblies.

As described in the previous post, nearly all WPF-functionality can be used in zenon. And depending on the functional requirements, programming knowledge might be required on user side. The goal of this post is to show how “easy” it is to create an own WPF-Control when more complex functionality is required. And how this WPF-Control, using an additional existing (in this case Microsoft) WPF-Assembly, can be used in zenon by use of the WPF-Element and Loose XAML.

Required: Let’s assume we want to display the values of 4 process variables (which could for example represent the amount of active alarms in 4 different alarm areas) in a bit of nicer way than just a bunch of numeric values. On demand (for example on function execution) we would like them, a description and their ratio to be displayed in a Pie-Styled Chart.

Solution:

We will be using the WPF-Element to display an XAML-File. This XAML-File will use a “custom” made WPF-Control which will display the internal variables and a matching description in a chart. The values of the internal variable will be passed on to the chart by use of a VBA-Macro. This VBA-macro uses the method “WPFProperty” which is offered by the Element-Object in the zenon-API. The macro will be executed by an “Execute VBA-Macro”-Function which will be triggered when pressing a Button-Element.

A customized Chart

Since quite some time Microsoft offers a WPF-Toolkit which included several ready-to-use WPF-Controls. This Toolkit (which is partly open source!) has been expanded more than once, and since June 2009 a so called “Chart”-control is one of them. The Chart control supports various styles (Column, Bar, Pie,Line,etc) but for our example we will stick to the “Pie” Style. We are going to create a .Net WPF-Assembly “ChartControlLibrary” that offers a “new” WPF-Control called “ChartControl”. The ChartControl will be based on the chart control from the WPF-Toolkit, but expanded for usage with zenon process values.

Creating the Project with Microsoft Expression Blend 3

We will be creating our control using “Microsoft Expression Blend 3”, so let’s start it! Upon startup we choose to create a new Project from type “WPF Control Library”

cialis

and name it “ChartControlLibrary”. After we confirmed the project type and name, a new solution is generated and opened in Blend. The new project by default includes an empty WPF-Control. Since renaming the default control would required additional changes to its underlying cs-file, we are simply going to delete it. Next we insert a new item to the project by use of the context menu in the project-tree. After choosing the item type

viagra pills

“UserControl” and entering the name “ChartControl” we confirm with “OK”.

Since we would like to use the Chart from the WPF-Toolkit, we add a reference to its core assembly “System.Windows.Controls.DataVisualization.Toolkit.dll”  to the project by use of the context menu in the project-tree (The WPF-Toolkit typically installs its assemblies to “C:\Program Files (x86)\WPF Toolkit\v3.5.40619.1”). Before we can use the WPF-Toolkit in our ChartControl we still have to expand the namespace declarations in the UserControl. We will be adding a new namespace declaration “charting” to the control which maps to the WPF-Toolkit assembly. This is done by adding the following line to the existing xmlns definitions:

xmlns:charting=clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit

Now, we are able to add an instance of the Toolkit-chart to our ChartControl by replacing the existing xaml-code “<Grid x:Name=”LayoutRoot”/>” with the following lines:

<Gridx:Name=LayoutRoot>

  <charting:Chartx:Name=chartClipToBounds=TrueHorizontalContentAlignment=StretchVerticalContentAlignment=StretchGrid.IsSharedSizeScope=False>

    <charting:Chart.Series>

      <charting:PieSeriesItemsSource={Binding}

          DependentValuePath=Value

          IndependentValuePath=Key

          IsSelectionEnabled=True />

    </charting:Chart.Series>

  </charting:Chart>

</Grid>

After doing this, the designview of our ChartControl should look like this:

This wraps up the design process, and now we can start with the actual “coding”. We will need a way to pass the zenon data (being values of internal variables and a matching description) on to the control. To offer this, we will be implementing a few properties in the control; which can be used from zenon. We would like to keep our ChartControl as flexible as possible, and although our current assignment is to display only 4 values, we could be required to show a different amount of values in the future. So instead of implementing fix properties like “value1”, “value2”, “value3” and “value4”, we will be implementing a set of properties which enable us to add an variable amount of values to the chart. So let’s start by implementing 2 properties which can be used to pass a value and a fitting value-name to the ChartControl. To store the information for these 2 properties we will add 2 members to the ChartControl-Class:

#region Member Variables

       //Description for the value which is being added to the chart.

       privatestring  m_strValueName=“”;

       //Value which is added to chart.

       privatedouble  m_dblValue=0;

#endregion

Next we will add the implementation of the 2 properties:

#region Public Properties

       ///<summary>

       /// Fake property used to pass the name of a value to the ChartControl.

       ///</summary>

       publicstring ValueName

       {

             get

             {

                    return m_strValueName;

             }

             set

             {

                    m_strValueName=value;

             }

       }

       ///<summary>

       /// Fake property used to pass a value to the ChartControl.

       ///</summary>

       publicdouble Value

       {

             get

             {

                    return m_dblValue;

             }

             set

             {

                    m_dblValue=value;

             }

       }

#endregion  

In order to display more than just one value and valuename, we are going to need to store the values and names in some sort of an array. And we will need some way of telling our ChartControl “ok, the current values of the properties represent one Chart-Dataset”. To do this we are going to implement a property “AddValue” which is more or less used as a method. Whenever the AddValue-Property is set, the current values of the Value-Properties will be added to a KeyValuePair-Array in the control by use of a function called “AddValueToChart”. After resizing the KeyValuePairArray, the function will pass the Array to the Chart-Control and will trigger an update of the Chart. Let’s add a the function in a new region “Private Methods” to the ChartControl-Class:

#region Private Methods

       ///<summary>

       /// Create/Expand the Chartdata Array and add the given Text and Value.

       ///</summary>

       ///<param name=”strText”>Tag for the data</param>

       ///<param name=”dblvalue”>Data</param>

       privatevoid AddValueToChart(string strText,double dblvalue)

       {

             if (m_Data == null)

             {

                    //No data available yet, let’s create a new KeyValuePairArray.

                    m_Data = new KeyValuePair<string, double>[1];

             }

             else

             {

                    //Let’s “expand” the existing Array containing the chartdata.

                    KeyValuePair<string, double>[] newData = new KeyValuePair<string, double>[m_Data.Length + 1];

                    System.Array.Copy(m_Data, newData, m_Data.Length);

                    m_Data = newData;

             }

             //Add the variabledata to the chartdata and udate the chart.

             m_Data.SetValue(new KeyValuePair<string, double>(strText, dblvalue), m_Data.Length – 1);

             chart.DataContext = m_Data;

             chart.UpdateLayout();            

       }

#endregion

Expand the Member Variables region with the definition of the KeyValueArray:

//Chartdata, containing Variable names and their Valuesprivate

KeyValuePair<string, double>[] m_Data = null; 

And expand the “Public Properties” region with the definition of the “AddValue” property:

///<summary>

/// Fake property which causes the previously set “Value” and “ValueName” to be add to the Chart.

/// Returns true when there’s currently data shown in the chart.

///</summary>

public Boolean AddValue

{

       get

       {

             return (m_Data!=null); 

       }

       set

       {

             //Let’s add the data to the chart.

             AddValueToChart(m_strValueName,m_dblValue);

       }

}

Now let’s build the solution, and if it succeeds : Were done in Blend! We can now use our own ChartControl in zenon by use of the WPF-Element and a XAML-file which links to the CharControlLibraray.dll. In order to do this we have to add all assemblies from the Ouput-Folder (ChartControlLibrary.dll, System.Windows.Controls.DataVisualization.Toolkit.dll and WPFToolkit.dll)to the “Others” files folder of a zenon-Project. The following xaml file (“Chart.XAML”) can be used in zenon by adding it to the “Graphics”-Folder.

<UserControl

      xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”

      xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”

      xmlns:d=”http://schemas.microsoft.com/expression/blend/2008″

      xmlns:mc=”http://schemas.openxmlformats.org/markup-compatibility/2006″

      mc:Ignorable=”d”

      xmlns:ChartControlLibrary=”clr-namespace:ChartControlLibrary;assembly=ChartControlLibrary”

      x:Name=”UserControl”

      d:DesignWidth=”640″ d:DesignHeight=”480″>

      <Grid x:Name=”LayoutRoot”>

            <ChartControlLibrary:ChartControl x:Name=”Chart1″ Margin=”0″/>

      </Grid>

</UserControl>

Let’s insert a new screen called “Screen1” and add a WPF-Element with the name “WPF-Element_1” to it. Next we select the “Chart.XAML” file from the properties of the WPF-Element. Hopefully (it should be) the Chart-Control will be displayed in a similar way as it was in the Design mode of Microsoft Expression Blend. But it’s still kind of boring since it’s not actually showing anything yet. So we create 4 new Internal Variables with the names “internal variable1″,”internal variable2″,”internal variable3” and “internal variable4”, which “represent” the alarm counters. Now we add 4 numeric value elements to the Screen, and connect each one of them to one of the variables. These are the values we will be displaying in the chart at Runtime. The next stop is to create a small VBA-Macro. The task of the macro is to take the values from the 4 internal variables and pass them on to the “Chart1”-Control in our XAML file. To do this we are using the “WPFProperty”-Method of the zenon.Element-object.

Public Sub PassDataDirect()

    Dim obElement As Element

    obElement = thisProject.DynPictures.Item(0).Elements.Item(“WPF-Element_1”)

    obElement.WPFProperty(“Chart1”, “ValueName”) = “Internal Variable 1”

    obElement.WPFProperty(“Chart1”, “Value”) = thisProject.Variables.Item(“internal variable1”).Value

    obElement.WPFProperty(“Chart1”, “AddValue”) = True

    obElement.WPFProperty(“Chart1”, “ValueName”) = “Internal Variable 2”

    obElement.WPFProperty(“Chart1”, “Value”) = thisProject.Variables.Item(“internal variable2”).Value

    obElement.WPFProperty(“Chart1”, “AddValue”) = True

    obElement.WPFProperty(“Chart1”, “ValueName”) = “Internal Variable 3”

    obElement.WPFProperty(“Chart1”, “Value”) = thisProject.Variables.Item(“internal variable3”).Value

    obElement.WPFProperty(“Chart1”, “AddValue”) = True

    obElement.WPFProperty(“Chart1”, “ValueName”) = “Internal Variable 4”

    obElement.WPFProperty(“Chart1”, “Value”) = thisProject.Variables.Item(“internal variable4”).Value

    obElement.WPFProperty(“Chart1”, “AddValue”) = True

End Sub

Next step will be to add a new Function (Name: “Func_VBA_Direct”, Type: Execute VBA-Macro) and configure it so it executes the “PassDataDirect” macro. We connect this function to a new Button-Element which we place onto “Screen1”. After we made sure that “Screen1” is set a the start-screen for the project, we compile and start the RT. By setting some random values to the internal variables followed by a click of the Button, the random values will be displayed in the ChartControl!

Files for this post

Source files for this post. Compiled assemblies.

System requirements:

  • zenon 6.51 or higher
  • WPF-Requirements as stated in the zenon documentation.
  • WPF-Toolkit:  (available from http://wpf.codeplex.com/ as a part of the Microsoft Shared Source Initiative).
  • Microsoft Expression Blend 3 or higher (only required for viewing and compiling the source solution).

Tags: , ,