Wednesday, December 10, 2008

Create a SharePoint AJAX-refreshable Web Part which wraps an ASP .NET Chart Control

Introduction

This tutorial includes the steps for making a SharePoint AJAX-refreshable Web Part which wraps an ASP .NET Chart Control.
This tutorial is the following of two previous ones:
  1. MOSS, How to...: Use Microsoft Chart Controls for .Net framework in a SharePoint web site
  2. MOSS, How to...: Use Microsoft ASP .NET Chart Control in a SharePoint Web Part
In this tutorial, we are going to put together three important ASP .NET compliant Microsoft features:
  • Windows SharePoint Services 3.0 Web parts
  • Microsoft ASP .NET Chart Control
  • Microsoft ASP .NET AJAX 3.5
Ajax integration with ASP .NET Chart Control will be easier than ever since we already had to use the .Net Framework 3.5 for the ASP .NET Chart Control, and that the most significant advance in ASP .NET with .NET Framework 3.5 is improved support for the developement of AJAX-enabled web sites.
This tutorial is compliant with both MOSS 2007 and Windows SharePoint Services 3.0.



In this SharePoint Web part Page, 4 SharePoint Web Parts embedding an ASP .NET Chart Control can be refreshed independently some of the others using ASP .NET AJAX 3.5 and can be used to build a SharePoint Dashboard.

1 - Prerequisites
2 - Important ASP .NET AJAX 3.5 information:
1 - Using UpdatePanel control and efficiency.
There are roughly two ways of doing Ajax with Microsoft Ajax Framework.
  • Using UpdatePanel control
  • Using a web Service. ( ASMX Web method called through the javaScript Proxy).
Using UpdatePanel control while adding AJAX functionality to an aspx page DOES NOT increase performances of the page since when UpdatePanel control performs an asynchronous AJAX callback to the server to update its content, the request contains everything a conventional ASP .NET postback contains, including view state.
Unfortunatly, as an ASP .NET Chart Control is a Server Conrol, the only (easy) way of adding AJAX improvements to an .aspx page regarding an ASP .NET Chart Control is to use Update Panel. Of course Best Practices in using UpdatePanel can increase the page efficiency.

For more information there is this article of Jeff Prosise in MSDN Magazine (june 2007 issue)
             MSDN Magazine : WICKED CODE - Update Panel Tips and Tricks 
2 - URL of the hosting SharePoint Web site
An article of Microsoft Knowledge Base reports that issue may occur if you use international characters in an URL of a SharePoint Page that contains a Web Part with ASP .NET AJAX Functionality. It is possible that this bug doesn't exist anymore with the ASP .NET AJAX 3.5 version.
For more information:
              A Web Part that contains an ASP.NET AJAX 1.0 UpdatePanel control that uses the _doPostBack() function does not work...
3 - Tutorial Overview
This tutorial includes the following steps:
  • Step 1: Configure your SharePoint environment for ASP .NET Ajax 3.5
  • Step 2: Create a new Class in AspNetChartControl.SharePointWebParts project
  • Step 3: Give the Class the Basic Structure for a SharePoint Web Part without forgetting the "public" class declaration.
  • Step 4: Define the Logic and rendering of your Web Part
  • Step 5: Implement Ajax functionality
  • Step 6: Build your web part
  • Step 7: Update the DLL already present in the web Application Bin Directory
  • Step 8: Import the site template default.aspx page in Visual Studio and rename it
  • Step 9: Add a Script Manager to the Web Part Page defaultWithScriptManager.aspx
  • Step 10: Add new Web Part Zones to the Web Part Page defaultWithScriptManager.aspx
  • Step 11: Import the Web Part Page defaultWithScriptManager.aspx into your Sharepoint Web Site.
  • Step 12: Import several Web Parts AjaxRefreshableChartWebPart into your Web Part Page.

4 - Tutorial
4.1 - Step 1: Configure your SharePoint environment for ASP .NET Ajax 3.5
We are going to add entries in the web.config file of the Web Application where is running the SharePoint Team site that is planned to welcome the Ajax-Refreshable Web part.
There is several way to modify this file in order to add support for .Net 3.5 in the SharePoint Web Application.
             CodePlex Feature automatic way
             SharePointOfView - WebConfigFeatureReceiver : This SPFeatureReceiver enable easy web.config modifications via an XML file. 
             Jan Tielen's lazy way
And the manual way that I have chosen to show here in its minimal version, in order to modify the web.config as little as possible since we have modified it yet for supporting ASP .NET Chart Control, and we have to use caution when modifying a Web Application web.config that is already complex enough.
Here are the steps (I have mentionned all of them ordered as in a SharePoint web.config file, but also mentionned the fact I have skipped some):
  • <config section> (skipped)
  • <SafeControls>
  • <httpHandlers>
  • <httpModules>
  • <assemblies>
  • <controls>
  • <system.web.extension> (skipped)
  • <system.web.server> (skipped)

  • <SafeControls>
    <!-- start adding -->
          <SafeControl Assembly="System.Web.Extensions, version=3.5.0.0, culture=Neutral, publicKeyToken=31bf3856ad364e35" Namespace ="System.Web.UI" TypeName="*" Safe="True" />
    <!-- end adding -->
    </SafeControls>
    
  • <httpHandlers>
          <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
          <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false" />
    
  • <httpModules>
          <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
  • <assemblies>
            <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> 
            <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
            <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> 
            <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> 
    
    
  • <controls>
          </tagMapping>
          <!-- start adding -->
          <controls>
            <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
            <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
            <add tagPrefix="asp" namespace="System.Web.UI.DataVisualization.Charting" assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
          </controls>
          <!-- end adding -->
        </pages>
    

4.2 - Step 2: Create a new Class in AspNetChartControl.SharePointWebParts project
To create a new class
  1. Right click your project in the Solution Explorer
  2. Select Add in the first menu
  3. Select Class in the second menu
  4. In the opening Dialog type the new Class name: AjaxRefreshableWebPart.cs
  5. Click Add.





This is the code state at the end of this step:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace AspNetChartControl.SharePointWebParts
{
    class AjaxRefreshableWebPart
    {
    }
}
4.3 - Step 3: Give the Class the Basic Structure for a SharePoint Web Part without forgetting the "public" class declaration.
Refering to previous tutorial from 3.2 to 3.5, give the Class the basic structure for a Sharepoint Web part Class.
This is the code state at the end of this step:
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.DataVisualization.Charting;
using System.Xml;
using System.Diagnostics;

namespace AspNetChartControl.SharePointWebParts
{
    [ToolboxData("<{0}:AjaxRefreshableWebPart runat=server></{0}:AjaxRefreshableWebPart>")]
    public class AjaxRefreshableWebPart : Microsoft.SharePoint.WebPartPages.WebPart
    {


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

        protected override void RenderWebPart(HtmlTextWriter output)
        {
            base.RenderWebPart(output);
        }
    }
}
4.4 - Step 4: Define the Logic and rendering of your Web Part
We are now using again one of the ASP .NET Chart Control Sample. In one of these samples (Stacked Charts), there is a piece of C# code that shows how to generate a random Chart Serie for a Chart Control. As we have not yet bound our Chart Control to a Data Source, we will use this random Chart Serie generation to simulate a real Data Source binding.



We have also to implement an ASP LinkButton to give user the chance to refresh the Web Part using it.
At the end of this step, we have a perfectly well working Wep Part, but it has not yet AJAX ability. That is to mean, if we build this code and deploy the Web Part, the click on the LinkButton will trigger a visible Postback of the Web Part Page.
This is the code state at the end of this step:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.DataVisualization.Charting;
using System.Xml;
using System.Diagnostics;

namespace AspNetChartControl.SharePointWebParts
{
    [ToolboxData("<{0}:AjaxRefreshableWebPart runat=server></{0}:AjaxRefreshableWebPart>")]
    public class AjaxRefreshableWebPart : Microsoft.SharePoint.WebPartPages.WebPart
    {

        System.Web.UI.DataVisualization.Charting.Chart Chart1;
        protected override void CreateChildControls()
        {
            base.CreateChildControls();

            LinkButton button1 = new LinkButton();
            button1.ID = "lButton1";
            button1.Text = "Refresh";
            button1.Click += new EventHandler(lButton_Click);

            Chart1 = new System.Web.UI.DataVisualization.Charting.Chart();

            Chart1.Width = 412;
            Chart1.Height = 296;
            Chart1.RenderType = RenderType.ImageTag;
            string imagespath = System.Configuration.ConfigurationSettings.AppSettings["ChartImageHandler"].ToString();
            Chart1.ImageLocation = imagespath + "ChartPic_#SEQ(200,30)";

            Chart1.Palette = ChartColorPalette.BrightPastel;
            Title t = new Title("Ajax-Refreshable ASP.NET Chart Control Web Part", Docking.Top, new System.Drawing.Font("Trebuchet MS", 14, System.Drawing.FontStyle.Bold), System.Drawing.Color.FromArgb(26, 59, 105));
            Chart1.Titles.Add(t);

            Chart1.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
            Chart1.BorderColor = System.Drawing.Color.FromArgb(26, 59, 105);
            Chart1.BorderlineDashStyle = ChartDashStyle.Solid;
            Chart1.BorderWidth = 2;

            if (Chart1.Series.FindByName("Series1") == null)
            {
                Chart1.Series.Add(new Series("Series1"));
                Chart1.ChartAreas.Add("Series1");
            }

            Random random = new Random();

            for (int pointIndex = 0; pointIndex < 10; pointIndex++)
            {
                Chart1.Series["Series1"].Points.AddY(random.Next(45, 95));
            }

            this.Controls.Add(Chart1);
            this.Controls.Add(button1);
        }

        void lButton_Click(object sender, EventArgs e)
        {
            Random random = new Random();

            for (int pointIndex = 0; pointIndex < 10; pointIndex++)
            {
                Chart1.Series["Series1"].Points.AddY(random.Next(45, 95));
            }
        }

        protected override void RenderWebPart(HtmlTextWriter output)
        {
            base.RenderWebPart(output);
        }
    }
}
4.5 - Step 5: Implement Ajax functionality
We are now going to give the Web Part its AJAX ability to be refreshed without triggering a visible Post Back. We know now that unfortunatly for the Page efficiency, UpdatePanel control trigger a PostBack, even if it is no visible.
For people that does not know at all how to use an UpdatePanel control, let's show the declarative syntax for that control that is very simple.
To use an UpdatePanel control in an ASP .NET Page and to give a piece of code the AJAX ability you just have to write that:
    <asp:ScriptManager ID="ScriptManager1" EnablePartialRendering="true" runat="server">
    </asp:ScriptManager>
        <asp:UpdatePanel ID="UpdatePanel1"  runat="server">
           <ContentTemplate>
              <!-- Place your code here -->
           </ContentTemplate>
        </asp:UpdatePanel>

Here is the previous code decorated with the implementation of the AJAX feature using the imperative syntax:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.DataVisualization.Charting;
using System.Xml;
using System.Diagnostics;

namespace AspNetChartControl.SharePointWebParts
{
    [ToolboxData("<{0}:AjaxRefreshableWebPart runat=server></{0}:AjaxRefreshableWebPart>")]
    public class AjaxRefreshableWebPart : Microsoft.SharePoint.WebPartPages.WebPart
    {

        System.Web.UI.DataVisualization.Charting.Chart Chart1;
        protected override void CreateChildControls()
        {
            base.CreateChildControls();
            
            //UpdatePanel declaration, instantiation and identification
            UpdatePanel updatePanel1 = new UpdatePanel();
            updatePanel1.ID = "udpAjaxRefreshableChartControlWebPart";
            //the way the of refreshing
            updatePanel1.UpdateMode = UpdatePanelUpdateMode.Conditional;

            LinkButton button1 = new LinkButton();
            button1.ID = "lButton1";
            button1.Text = "Refresh";
            button1.Click += new EventHandler(lButton_Click);

            Chart1 = new System.Web.UI.DataVisualization.Charting.Chart();

            Chart1.Width = 412;
            Chart1.Height = 296;
            Chart1.RenderType = RenderType.ImageTag;
            string imagespath = System.Configuration.ConfigurationSettings.AppSettings["ChartImageHandler"].ToString();
            Chart1.ImageLocation = imagespath + "ChartPic_#SEQ(200,30)";

            Chart1.Palette = ChartColorPalette.BrightPastel;
            Title t = new Title("Ajax-Refreshable ASP.Net Chart Control Web Part", Docking.Top, new System.Drawing.Font("Trebuchet MS", 14, System.Drawing.FontStyle.Bold), System.Drawing.Color.FromArgb(26, 59, 105));
            Chart1.Titles.Add(t);

            Chart1.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
            Chart1.BorderColor = System.Drawing.Color.FromArgb(26, 59, 105);
            Chart1.BorderlineDashStyle = ChartDashStyle.Solid;
            Chart1.BorderWidth = 2;

            if (Chart1.Series.FindByName("Series1") == null)
            {
                Chart1.Series.Add(new Series("Series1"));
                Chart1.ChartAreas.Add("Series 1");

            }

            Random random = new Random();
            Debug.WriteLine("AjaxRefreshWebPart - CreateChildControls");


            for (int pointIndex = 0; pointIndex < 10; pointIndex++)
            {
                Chart1.Series["Series1"].Points.AddY(random.Next(45, 95));
            }

            //the controls are embedded inside the UpdatePanelControl
            updatePanel1.ContentTemplateContainer.Controls.Add(Chart1);
            updatePanel1.ContentTemplateContainer.Controls.Add(button1);

            this.Controls.Add(updatePanel1);
        }

        void lButton_Click(object sender, EventArgs e)
        {
            Random random = new Random();

            for (int pointIndex = 0; pointIndex < 10; pointIndex++)
            {
                Chart1.Series["Series1"].Points.AddY(random.Next(45, 95));
            }
        }

        protected override void RenderWebPart(HtmlTextWriter output)
        {
            base.RenderWebPart(output);
        }
    }
}
4.6 - Step 6 : Build your web part
After you add all of the preceding code, you can build your sample Web Part.

To build your Web Part
On the Build menu, click Build Solution.
4.7 - Step 7: Update the DLL already present in the web Application Bin Directory
After the Web Part is built, you must copy the resulting DLL to the bin directory. To copy your DLL to the bin directory

  1. On the file system, locate the AspNetChartControl.SharePointWebparts.dll file. It should be in
    C:\AspNetChartControl.SharePointWebparts\AspNetChartControl.SharePointWebparts\bin\Debug.
  2. Replace the AspNetChartControl.SharePointWebParts.dll in the the Web application root bin directory with the file from the output directory.
4.8 - Step 8: Import the site template default.aspx page in Visual Studio and rename it
Navigate to the following directory
C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\SiteTemplates\sts
Copy the default.aspx page and paste it in your project directory.
In the Visual Studio Solution Explorer click Display All Files button to make the default.aspx page to be visible.
Right click the page and click on "Include In Project".
Rename the page in "defaultWithScriptManager.aspx"



4.9 - Step 9: Add a Script Manager to the Web Part Page defaultWithScriptManager.aspx
open the Page in Code view
Expand Visual Studio Toolbox and locate the ScriptManager control and drag it.



Locate the first WepPartZone declaration and drop a ScriptManager instance upon it.




4.10 - Step 10: Add new Web Part Zones to the Web Part Page defaultWithScriptManager.aspx
Locate the HTML <tr> line that contains the 2 webPartZone and duplicate it.



Rename the 4 WebPartZones in order to obtain the following HTML code:
         <table width="100%" cellpadding=0 cellspacing=0 style="padding: 5px 10px 10px 10px;">
          <tr>
           <td valign="top" width="70%">
               <asp:ScriptManager ID="ScriptManager1" runat="server">
               </asp:ScriptManager>
               <WebPartPages:WebPartZone runat="server" FrameType="TitleBarOnly" ID="LeftUp" Title="loc:LeftUp" />
               &nbsp;
           </td>
           <td>&nbsp;</td>
           <td valign="top" width="30%">
               <WebPartPages:WebPartZone runat="server" FrameType="TitleBarOnly" ID="RightUp" Title="loc:RightUp" />
               &nbsp;
           </td>
           <td>&nbsp;</td>
          </tr>
                    <tr>
           <td valign="top" width="70%">
               <WebPartPages:WebPartZone runat="server" FrameType="TitleBarOnly" ID="LeftDown" Title="loc:LeftDown" />
               &nbsp;
           </td>
           <td>&nbsp;</td>
           <td valign="top" width="30%">
               <WebPartPages:WebPartZone runat="server" FrameType="TitleBarOnly" ID="RightDown" Title="loc:RightDown" />
               &nbsp;
           </td>
           <td>&nbsp;</td>
          </tr>
         </table>
When the changes are done, save the page.
4.11 - Step 11: Import the Web Part Page defaultWithScriptManager.aspx into your Sharepoint Web Site.
Go to the Shared Documents document library of your team site and select upload a document.


Then navigate to your project directory and choose the defaultWithScriptManager.aspx page.





4.12 - Step 12: Import several Web Parts AjaxRefreshableWebPart into your Web Part page.
Now you can add 4 AjaxRefeshableChartControlWebParts in your Page.



And notice that you can rename them, and they can be refreshed independently some of the others using ASP .NET AJAX 3.5 and can be used to build a SharePoint Dashboard.



5 - For more information
You can find additional information at: I plan writing soon a post on Data Binding for these Web Parts, and a more generic article on dashboards with WSS 3.0.
By the way, there will be an interesting conference on that topic in february:
Case Studies in SharePoint Dashboards - The Sequel
If you are planning to realize such dashboards using ASP .NET Chart Controls, I will be pleased to exchange information with you...

Thursday, December 4, 2008

Use a Microsoft Asp .Net Chart Control in a SharePoint Web Part

Introduction

This tutorial includes the steps for creating a basic custom Windows SharePoint Services Web Part which wraps a Microsoft Chart Control for ASP .Net. It is a simple Web Part that allows you to change the Enabled property of the ASP .Net Chart control's legend. The System.Web.UI.DataVisualization.Charting.Legend class is used to manage the legend of the Asp .Net Chart.
The goal of this tutorial was to place inside a Web Part the "Chart without Code-Behind" sample, that is one of the 200 Interactive Samples for Asp .Net Chart Control from Samples Environment for Microsoft Chart Controls .



This also, shows how to develop quickly : test your solution in "in line" script, then, deploy it using a component, as I wrote before in
              Improve speed of development for SharePoint (Part3) - Using in line scripts in SharePoint programming 
This tutorial is compliant with both MOSS 2007 and Windows SharePoint Services.

Beginning with Windows SharePoint Services 3.0, the Windows SharePoint Services Web Part infrastructure is built on top of the Microsoft ASP.NET 2.0 Web Part infrastructure and Web Parts that derive from the ASP.NET WebPart class are completely supported in Windows SharePoint Services. You should create ASP.NET Web Parts whenever possible.
For more information about choosing the best Web Part base class from which to derive, see Developing Web Parts in Windows SharePoint Services in the Windows SharePoint Services Software Development Kit (SDK). For more information about ASP.NET Web Parts, see the Web Parts Control Set Overview in the ASP.NET documentation.

To see a much more complete example of a Web Part wrapping an ASP .net Chart Control, you can go to CodePlex and examine the
                      Wictor Wilén's ChartPart.
Wictor Wilén's ChartPart derive from ASP .Net WebPart class. The one of this tutorial derive from Windows SharePoint Services Web Part Class.

1 - Prerequisites

  • Usual development environment for SharePoint (Windows 2003 Server or Windows Server 2008 with a SharePoint installation).
  • Microsoft Chart Controls for Microsoft .NET Framework 3.5 are installed on the development environment. You can download installation package here
  • Microsoft Visual Studio 2008 is installed on the development environment.
  • Microsoft Chart Controls Add-on for Microsoft Visual Studio 2008 is installed on the development environment.
  • Samples Environment for Microsoft Asp .Net Chart Controls is installed on the development environment.
  • Your SharePoint environement is properly configured for ASP .Net Chart Controls. If you are not sure you can check the configuration in my previous post, sections 3.3 and 3.4, or do this previous post quick tutorial in order to validate your environment by displaying the Chart Control Sample on a SharePoint page.
                      Use Microsoft Chart Controls for .NET Framework in a SharePoint web site  
    
  • You have a SharePoint team site ready to welcome the Asp .Net Chart control Web part.

2 - Tutorial Overview

This tutorial includes the following steps:
  • Step 1: Create an ASP .Net Server Control project
  • Step 2: Add a reference to Microsoft.SharePoint.dll, System.Web.DataVisualization.dll and regarding Namespace Directives
  • Step 3: Rename the Class
  • Step 4: Inherit from the Web part Class
  • Step 5: Use the RenderWebpartMethod
  • Step 6: Define the Logic and rendering of your Web Part using Asp .Net Chart Control Samples and the CreateChildControls Method
  • Step 7: Build your web part
  • Step 8: Copy your DLL to the Bin Directory
  • Step 9: Add ControlSafe Entry in the Web Application web.config
  • Step 10: Import the site template default.aspx page and use it as a Web Part page
  • Step 11: Import the ASP .Net Chart Control Web Part into your Web Part page.
Warning: I skipped some steps in order to give a quick result. To be really compliant with the SharePoint Web Part development best practices refer to:
             MSDN: Walkthrough: Creating a Basic SharePoint Web Part

3 - Tutorial

3.1 Step 1: Create an ASP .Net Server Control project
To create a new ASP .Net Server Control project
  1. Start Visual Studio 2008.
  2. On the File menu, point to New, and then click Project.
  3. In the New Project dialog box, click Visual C# Projects or Visual Basic Projects, and then select the ASP .Net Server Control project template.
  4. Type AspNetChartControl.SharePointWebParts as the name and specify the location for the project files, and then click OK.




3.2 Step 2: Add a reference to Microsoft.SharePoint.dll, System.Web.DataVisualization.dll and regarding Namespace Directives
To create a Web Part, you need to add a reference to the Microsoft.SharePoint assembly (Microsoft.SharePoint.dll) in your Web Control Library project.
To add a reference to Microsoft.SharePoint.dll
  1. On the Project menu, click Add Reference.
  2. On the .NET tab, double-click Windows SharePoint Services.
  3. Click OK.



To make it easier to write a basic WebPart class, you should use the using directive in C# or the Imports directive in Visual Basic to reference the following namespace in your code:
The Microsoft.SharePoint.WebPartPages namespace provides the types for Web Part pages, such as the Microsoft.SharePoint.WebPartPages.WebPart class.



As we are going to use a Microsoft Asp .Net Chart Control in our web part, we have to do exactly the same for the System.Web.DataVisualization.dll and regarding System.Web.UI.DataVisualization.Charting namespace.





3.3 Step 3: Rename the Class and clean up the code
To rename the class
  1. In the solution explorer right click the class file and select rename
  2. Rename the file in DynamicLegendWebPart (don't forget extension)
  3. Click ok on the message box that will ask you to rename the other instance of the clas name inside your source code.
Don't forget to rename the parameter of the ToolBoxData Attribute.
As we won't use any property for this web part, delete the "Text" property, the corresponding class attribute and the reference in the Render Content Method.



This is the code state at the end of this step:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebPartPages;

namespace AspNetChartControl.SharePointWebParts
{
    [ToolboxData("<{0}:DynamicLegendWebPart runat=server></{0}:DynamicLegendWebPart>")]
    public class DynamicLegendWebPart : WebControl
    {


        protected override void RenderContents(HtmlTextWriter output)
        {

        }
    }
}
3.4 Step 4: Inherit from the Web part Class
By default, the Web Control Library template creates a custom control that inherits from the System.Web.UI.Control class (a parent class of both the ASP.NET and SharePoint WebPart classes).
To create a SharePoint Web Part, you should inherit from the Microsoft.SharePoint.WebPartPages.WebPart base class.

To inherit from the Web Part base class.

Replace this line of code:
public class DynamicLegendWebPart : WebControl 
with this line:
public class DynamicLegendWebPart : WebPart
This is the code state at the end of this step:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebPartPages;

namespace AspNetChartControl.SharePointWebParts
{
    [ToolboxData("<{0}:DynamicLegendWebPart runat=server></{0}:DynamicLegendWebPart>")]
    public class DynamicLegendWebPart : WebPart
    {


        protected override void RenderContents(HtmlTextWriter output)
        {

        }
    }
}

3.5 Step 5: Use the RenderWebpartMethod
The WebPart base class seals the Render method of System.Web.UI.Control because the Web Part infrastructure needs to control rendering the contents of a Web Part. For this reason, custom Web Parts must override the RenderWebPart method of the WebPart base class.
To use the RenderWebPart method.
Replace this line of code:

protected override void RenderContents(HtmlTextWriter output)
with this line:
protected override void   RenderWebPart(HtmlTextWriter output)
3.6 Step 6: Define the Logic and rendering of your Web Part using Asp .Net Chart Control Samples and the CreateChildControls Method


After you complete the previous steps, you can define the logic and rendering for your Web Part. For this part, we will, as annouced previously, rewrite the in-line code of the "Chart Without Code Behind" Sample, in order to make this sample work inside a web part.



The steps are the following :
  1. Write a CreateChildControls Method to add the Asp .Net Chart Control and the CheckBox Control as child controls of the Web Part
  2. Inside this method:
    • add text and Autopostback to the CheckBox
    • Change the image location definition using our web.config AppSettings
    • Change the Chart Title
    • Add the controls as children
  3. Move the render instruction to the RenderWebPart Method
  4. Override OnLoad Method in order to see the changes after the PostBack
  5. Place the Legend Enabling instructions inside the OnLoad Method
  6. Move the declaration and instanciation instructions for the two child controls outside the methods in order to factorize them.


Here is the complete code before rewriting with the TODO instructions:
  <%
                        //put this at the top of the class to this to be shared by all the methods
                        System.Web.UI.DataVisualization.Charting.Chart Chart1 = new System.Web.UI.DataVisualization.Charting.Chart();
                        //declare and instantiate the checkBox control in the same place and way
                        
                        //All the following (untill next method instruction) go Inside CreateChildControls Method
                        //Set the text property value of the Checkbox control to "Show Legend"
                        //Set the AutoPostBack porperty value to true
                        
                        Chart1.Width = 412;
                        Chart1.Height = 296;
                        Chart1.RenderType = RenderType.ImageTag;
                        //Use the AppSettings to retrieve the path from our web.config
                        Chart1.ImageLocation = "..\\..\\TempImages\\ChartPic_#SEQ(200,30)";
                        
                        Chart1.Palette = ChartColorPalette.BrightPastel;
                        //Change the title to " Dynamic Legend SharePoint Web Part with ASP .net Chart Control"
                        Title t = new Title("No Code Behind Page", Docking.Top, new System.Drawing.Font("Trebuchet MS", 14, System.Drawing.FontStyle.Bold), System.Drawing.Color.FromArgb(26, 59, 105));
                        Chart1.Titles.Add(t);
                        Chart1.ChartAreas.Add("Series 1");
                        // create a couple of series
                        Chart1.Series.Add("Series 1");
                        Chart1.Series.Add("Series 2");
                        
                        
                        // add points to series 1
                        Chart1.Series["Series 1"].Points.AddY(5);
                        Chart1.Series["Series 1"].Points.AddY(8);
                        Chart1.Series["Series 1"].Points.AddY(12);
                        Chart1.Series["Series 1"].Points.AddY(6);
                        Chart1.Series["Series 1"].Points.AddY(9);
                        Chart1.Series["Series 1"].Points.AddY(4);
                         
                        // add points to series 2
                        Chart1.Series["Series 2"].Points.AddY(2);
                        Chart1.Series["Series 2"].Points.AddY(6);
                        Chart1.Series["Series 2"].Points.AddY(18);
                        Chart1.Series["Series 2"].Points.AddY(16);
                        Chart1.Series["Series 2"].Points.AddY(21);
                        Chart1.Series["Series 2"].Points.AddY(14);
                          
                        Chart1.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
                        Chart1.BorderColor = System.Drawing.Color.FromArgb(26, 59, 105);
                        Chart1.BorderlineDashStyle = ChartDashStyle.Solid;
                        Chart1.BorderWidth = 2;
                        
                        Chart1.Legends.Add("Legend1");
                        
                            // show legend based on check box value
                        //Put this in OnLoad Method 
                        Chart1.Legends["Legend1"].Enabled = ShowLegend.Checked;
                        //Put this in the RenderWebPart Method with the correct syntax
                        // Render chart control
                        Chart1.Page = this;
                        HtmlTextWriter writer = new HtmlTextWriter(Page.Response.Output);
                        Chart1.RenderControl(writer);
                    
                     %>
                     <!-- Make a child control of the web part with all the following -->
                    </td>
                    <td valign="top">
                        <table class="controls" cellpadding="4">
                            <tr>
                                <td class="label48"></td>
                                <td>
                                    <p><asp:checkbox id="ShowLegend" runat="server" Text="Show Legend" AutoPostBack="True"></asp:checkbox></p>
                                </td>
                            </tr>
                        </table>

Here is the complete code after rewriting: DynamicLegendWebpart.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Web.UI.DataVisualization.Charting;
namespace AspNetChartControl.SharePointWebParts
{
    [ToolboxData("<{0}:DynamicLegendWebPart runat=server></{0}:DynamicLegendWebPart>")]
    public class DynamicLegendWebPart : WebPart
    {
        System.Web.UI.DataVisualization.Charting.Chart Chart1 = new System.Web.UI.DataVisualization.Charting.Chart();
        CheckBox ShowLegend = new CheckBox();
        protected override void OnLoad(EventArgs e)
        {
            Chart1.Legends.Add("Legend1");
            Chart1.Legends["Legend1"].Enabled = ShowLegend.Checked;
        }
        protected override void CreateChildControls()
        {
            ShowLegend.AutoPostBack = true;
            ShowLegend.Text = "Show Legend ";
            Chart1.Width = 412;
            Chart1.Height = 296;
            Chart1.RenderType = RenderType.ImageTag;
            string imagespath = System.Configuration.ConfigurationSettings.AppSettings["ChartImageHandler"].ToString();
            Chart1.ImageLocation = imagespath + "ChartPic_#SEQ(200,30)";
            Chart1.Palette = ChartColorPalette.BrightPastel;
            Title t = new Title("Dynamic Legend Web Part with ASP .Net Chart Control", Docking.Top, new System.Drawing.Font("Trebuchet MS", 14, System.Drawing.FontStyle.Bold), System.Drawing.Color.FromArgb(26, 59, 105));
            Chart1.Titles.Add(t);
            Chart1.ChartAreas.Add("Series 1");
            // create a couple of series
            Chart1.Series.Add("Series 1");
            Chart1.Series.Add("Series 2");
            // add points to series 1
            Chart1.Series["Series 1"].Points.AddY(5);
            Chart1.Series["Series 1"].Points.AddY(8);
            Chart1.Series["Series 1"].Points.AddY(12);
            Chart1.Series["Series 1"].Points.AddY(6);
            Chart1.Series["Series 1"].Points.AddY(9);
            Chart1.Series["Series 1"].Points.AddY(4);
            // add points to series 2
            Chart1.Series["Series 2"].Points.AddY(2);
            Chart1.Series["Series 2"].Points.AddY(6);
            Chart1.Series["Series 2"].Points.AddY(18);
            Chart1.Series["Series 2"].Points.AddY(16);
            Chart1.Series["Series 2"].Points.AddY(21);
            Chart1.Series["Series 2"].Points.AddY(14);
            Chart1.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
            Chart1.BorderColor = System.Drawing.Color.FromArgb(26, 59, 105);
            Chart1.BorderlineDashStyle = ChartDashStyle.Solid;
            Chart1.BorderWidth = 2;
            this.Controls.Add(Chart1);
            this.Controls.Add(ShowLegend);
        }
        protected override void RenderWebPart(HtmlTextWriter output)
        {
            // Render chart control and checkBox
            RenderChildren(output);
        }
    }
}
3.7 Step 7: Build your web part
After you add all of the preceding code, you can build your sample Web Part.

To build your Web Part
On the Build menu, click Build Solution.
3.8 Step 8: Copy your DLL to the Bin Directory
After the Web Part is built, you must copy the resulting DLL to the bin directory. To copy your DLL to the bin directory
  1. On the file system, locate the AspNetChartControl.SharePointWebparts.dll file. It should be in
    C:\AspNetChartControl.SharePointWebparts\AspNetChartControl.SharePointWebparts\bin\Debug.
  2. Copy the AspNetChartControl.SharePointWebParts.dll file from the output directory to the Web application root bin directory. The default location of the Web application root for is C:\Inetpub\wwwroot\wss\VirtualDirectories\PortNumber\bin.




3.9 Step 9: Add ControlSafe Entry in the Web Application web.config
I skipped some steps required to be compliant with the best practices, for the demonstration to be quick. But you should usually:
  • compile the dll with a strong name and an AllowPartiallyTrustedCallers attribute
  • at least modify the trust level of the web.config and the best would be to use Code Access Security policies
.Anyway for a fast demonstration, with just adding the non-signed dll in the bin directory and this entry in the web.config, it works !
 <SafeControl Assembly="AspNetChartControl.SharePointWebParts" Namespace="AspNetChartControl.SharePointWebParts" TypeName="*" Safe="true" />
<SafeControls />
3.10 Step 10: Import the site template default.aspx page and use it as a Web Part page
I want now to show an amazing trick to have quickly a web Part Page with a master page, especially for people who just have WSS 3.0.
Go to the Shared Documents document library of your team site and select upload a document.



Then navigate to the following directory
C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\SiteTemplates\sts
and choose the default.aspx page.



You have now in the Shared Documents library a brand new Web Part Page with the Quick Launch menu !



3.11 Step 11: Import the ASP .Net Chart Control Web Part into your Web Part page.


To import your Web Part

Navigate to the site collection settings of your site, on the Site Settings page, click Web Parts under the Galleries heading.




In the Web Part Gallery, click New.
Locate and check AspNetChartControl.SharePointWebParts.DynamicLegendWebPart



Click on button Populate Gallery

The Web part is now available in the Web part gallery



Navigate back to the Web Part page. In the Web Part page, click Site Actions, and select Edit Page.

In your preferred zone, click Add a Web Part and check the box next to DynamicLegendWebPart in the dialog box. Click Add.





After the Web Part is added to the zone, check and uncheck the Show Legend CheckBox to test the Web Part.





Saturday, November 29, 2008

Use Microsoft Chart Controls for .NET Framework in a SharePoint web site

Introduction

This tutorial shows how to use Microsoft Chart Controls for .NET Framework in a SharePoint web site. I will post soon a new tutorial that will show how to integrate a chart in a SharePoint Web Part in order to configure the Chart Control through the Web Part Tool Pane. This tutorial is compliant both with MOSS and Windows SharePoint Services.
1 - Prerequisites
  • Microsoft Chart Controls for Microsoft .NET Framework 3.5 are installed on the development environment. You can download installation package here
  • Microsoft Visual Studio 2008 is installed on the development environment.
  • Microsoft Chart Controls Add-on for Microsoft Visual Studio 2008 is installed on the development environment. You can download it here .
  • Samples Environment for Microsoft Chart Controls are installed on the development environment. If not you can download them here.
You can check that System.Web.DataVisualization.dll is in the GAC



2 - Tutorial Overview
This tutorial presents the following operations:
  • Creating a asp .net Web Site and an in line script .aspx page to test a Chart Control.
  • Creating a SharePoint team Site where the previous aspx page will be deployed.
  • Copy the Web Samples images under the SharePoint 12 hive.
  • Modify the SharePoint site Web Application config file in order to make the chart controls to be usable in the SharePoint site.
  • Deploy the .aspx page in the SharePoint site and test it.
3 - Tutorial
3.1 Creating a asp .net Web Site and an in line script .aspx page to test a Chart Controls.
First create a web site project with Visual Studio 2008. Add a new Web Form to your web site and choose to put server code in line. Asume you call it MsChartControlForSharePoint.aspx
Then view your page in desgin mode and drag and drop a Chart control from the Tool Box of Visual Studio to your page.



Then put the following server script in your page
    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            // Create new data series and set it's visual attributes
            Series series = new Series("Spline");
            series.ChartType = SeriesChartType.Spline;
            series.BorderWidth = 3;
            series.ShadowOffset = 2;
            // Populate new series with data
            series.Points.AddY(67);
            series.Points.AddY(57);
            series.Points.AddY(83);
            series.Points.AddY(23);
            series.Points.AddY(70);
            series.Points.AddY(60);
            series.Points.AddY(90);
            series.Points.AddY(20);
            // Add series into the chart's series collection
            Chart1.Series.Add(series);
        }         
    </script>


here is the MsChartControlForSharePoint.aspx page complete code:

 <%@ Page Language="C#" %> 
 <%@ Register Assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
    Namespace="System.Web.UI.DataVisualization.Charting" TagPrefix="asp" %>
 <%@ Import Namespace="System.Web.UI.DataVisualization.Charting" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
    <title></title>

    <script runat="server">
        protected void Page_Load(object sender, EventArgs e)
        {
            // Create new data series and set it's visual attributes
            Series series = new Series("Spline");
            series.ChartType = SeriesChartType.Spline;
            series.BorderWidth = 3;
            series.ShadowOffset = 2;

            // Populate new series with data
            series.Points.AddY(67);
            series.Points.AddY(57);
            series.Points.AddY(83);
            series.Points.AddY(23);
            series.Points.AddY(70);
            series.Points.AddY(60);
            series.Points.AddY(90);
            series.Points.AddY(20);

            // Add series into the chart's series collection
            Chart1.Series.Add(series);
        }    
        
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Chart ID="Chart1" runat="server" Width="694px">
            <Series>
                <asp:Series Name="Series1">
                </asp:Series>
            </Series>
            <ChartAreas>
                <asp:ChartArea Name="ChartArea1">
                </asp:ChartArea>
            </ChartAreas>
        </asp:Chart>
    </div>
    </form>
</body>
</html>


Right click your page and choose "view in browser", you should obtain that result:



3.2 Creating a SharePoint team Site where the previous aspx page will be deployed.
Create a new Sharepoint Web application, then a site collection, and choose "Team Site" as site template.



3.3 Copy the Web Samples images under the SharePoint 12 hive.
Open the file where you unziped Web Samples and locate Images folder. Copy the content of the folder.



Under the 12 hive create a sub-directory "MicrosoftChartControls" in the IMAGES directory. Paste the previously copied images.



3.4 Modify the SharePoint site Web Application config file in order to make the chart controls to be usable in the SharePoint site.
Add a line to SafeControl Section
      <SafeControl Assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"  Namespace="System.Web.UI.DataVisualization.Charting" TypeName="*" Safe="True" AllowRemoteDesigner="True"/>
    </SafeControls>


Add the path="ChartImg.axd" line to httpHandlers section
    <httpHandlers>
      <remove verb="GET,HEAD,POST" path="*" />
      <add verb="GET,HEAD,POST" path="*" type="Microsoft.SharePoint.ApplicationRuntime.SPHttpHandler, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
      <add verb="OPTIONS,PROPFIND,PUT,LOCK,UNLOCK,MOVE,COPY,GETLIB,PROPPATCH,MKCOL,DELETE,(GETSOURCE),(HEADSOURCE),(POSTSOURCE)" path="*" type="Microsoft.SharePoint.ApplicationRuntime.SPHttpHandler, Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
      <add verb="*" path="ChartImg.axd" type="System.Web.UI.DataVisualization.Charting.ChartHttpHandler, System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="false"/>
    </httpHandlers>


Add a appSettings section
Go to the end of the web.config file and locate the ending tag </System.Workflow.ComponentModel.WorkflowCompiler>. Paste the appSettings section.
    </System.Workflow.ComponentModel.WorkflowCompiler>
    <appSettings>
      <add key="ChartImageHandler" value="storage=memory;timeout=20;URL=/_layouts/Images/MicrosoftChartControls/" />
    </appSettings>


As we are going to deploy the MsChartControlForSharePoint.aspx page in the Shared Document library of the SharePoint site , and there is in line code in it, we have to modify again the web.config in order to allow in line script to be executed in that page. Of course this is just for a matter of demonstration and is not a best practice at all. I will publish soon a post in order to deploy the control inside a Web Part.
Locate the "PageParserPaths" section and paste the "PageParserPath" line.
  <SharePoint>
    <SafeMode MaxControls="200" CallStack="false" DirectFileDependencies="10" TotalFileDependencies="50" AllowPageLevelTrace="false">
      <PageParserPaths>
          <PageParserPath VirtualPath="/Shared Documents/*" AllowServerSideScript="true" CompilationMode="Always"/>
        </PageParserPaths>
    </SafeMode>


3.5 Deploy the .aspx page in the SharePoint site and test it.
Now we just have to upload the MsChartControlForSharePoint.aspx page in the Shared Document library.







and test it.



4 - Related Links
You can find additional information at: Thanks to Alex Gorev for having referenced this post.