Another ASP.NET WebParts Connections Sample
July 2004
Summary:
This article shows another sample of using WebParts.
In this case we will create two WebParts:
- Author WebPart that displays the list of authors in the database.
- Books WebPart that displays the list of books in the database.
Both WebParts are completely independent from each other.
However when a user chooses to connect them, the Authors WebPart provides an IField interface to the Books webpart that is used to filter the books so only the ones from the selected author will be displayed.
We will also show other features of WebParts to illustrate how a user can add WebParts to his page that are only available through the Catalog not already in the page.
Visits:
Lets first show the code.
To run this sample you have to create a new WebSite in Visual Web Developer Express
or use Visual Studio .NET 2005 (or just create a virtual directory in IIS).
The Page
Lets start by showing how simple the page is:
Save the following code in a file with the extension .ASPX:
<%@ Page Language="C#" %>
<%@ Register TagPrefix="my" Namespace="MyWebParts" %>
<html>
<head runat="server">
<title>WebParts Sample</title>
</head>
<body>
<form id="form1" runat="server">
<asp:WebPartManager runat="server" ID="WPM" />
<asp:WebPartPageMenu runat="server" ID="WPPM" />
<asp:WebPartZone runat="server" ID="Zone1"
/>
<asp:ConnectionsZone runat="server" ID="connectionsZone1" />
<asp:CatalogZone runat="server" ID="catalogZone1">
<ZoneTemplate>
<asp:DeclarativeCatalogPart runat="server" ID="declarative1">
<WebPartsTemplate>
<my:AuthorWebPart runat="server" ID="author1" Title="Authors" />
<my:BooksWebPart runat="server" ID="books1" Title="Books" />
</WebPartsTemplate>
</asp:DeclarativeCatalogPart>
<asp:PageCatalogPart runat="Server" ID="pageCatalog1" />
</ZoneTemplate>
</asp:CatalogZone>
</form>
</body>
</html>
The first thing to notice is that we are not adding any WebPart to the WebPartZone,
the WebParts are only "declared" to be available using a CatalogZone, in this case
we are using the DeclarativeCatalogPart that allows to define a set of WebParts
that are available for the user.
We also added to the page a WebPartPageMenu that will allow us to move between the
different display modes of WebParts.
The WebParts
Save the following code into a file named MyWebParts.cs or MyWebParts.vb and save it inside a Code
directory inside the virtual directory.
C# Code
namespace MyWebParts {
using System;
using System.Drawing;
using System.ComponentModel;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
/// <summary>
/// WebPart to display the information of Authors
/// </summary>
public class AuthorWebPart : WebPart, IField {
GridView _view;
public AuthorWebPart() {
}
protected override void CreateChildControls() {
_view = new GridView();
_view.ID = "_authorsGrid";
_view.AutoGenerateColumns = true;
_view.DataKeyNames = new string[] { "au_id" };
CommandField field = new CommandField();
_view.SelectedRowStyle.BackColor = Color.Red;
field.ShowSelectButton = true;
_view.Columns.Add(field);
SqlDataSource ds = new SqlDataSource();
ds.ID = "_authorsDS";
ds.ConnectionString = "server=carlosagmail;database=pubs;uid=sa;pwd=yourpassword";
ds.SelectCommand = "select au_id, au_lname, au_fname from authors";
_view.DataSourceID = ds.ID;
this.Controls.Add(ds);
this.Controls.Add(_view);
}
[ConnectionProvider("AuthorID")]
public IField GetAuthor() {
return this;
}
#region IField Members
object IField.FieldValue {
get {
return _view.SelectedValue;
}
}
PropertyDescriptor IField.Schema {
get {
return TypeDescriptor.GetProperties(this.GetType())["FieldValue"];
}
}
#endregion
}
/// <summary>
/// WebPart to display the information
of Books
/// </summary>
public class BooksWebPart : WebPart {
private IField _authorField;
SqlDataSource _ds;
[ConnectionConsumer("Author")]
public void SetAuthor(IField field) {
this._authorField = field;
}
protected override void CreateChildControls() {
GridView view = new GridView();
view.ID = "_booksGrid";
view.AutoGenerateColumns = true;
view.DataKeyNames = new string[] { "title_id" };
CommandField field = new CommandField();
view.SelectedRowStyle.BackColor = Color.Red;
field.ShowSelectButton = true;
view.Columns.Add(field);
_ds = new SqlDataSource();
_ds.ID = "_booksDS";
_ds.ConnectionString = "server=carlosagmail;database=pubs;uid=sa;pwd=yourpassword";
view.DataSourceID = _ds.ID;
this.Controls.Add(_ds);
this.Controls.Add(view);
}
protected override void OnPreRender(EventArgs e) {
const string selectStatement = "SELECT titles.title_id, titles.title, titles.type, titles.price, titles.pubdate FROM titles";
EnsureChildControls();
if (_authorField != null) {
if (_ds.SelectParameters.Count == 0) {
_ds.SelectCommand = selectStatement + " INNER JOIN titleauthor ON titleauthor.title_id = titles.title_id WHERE (titleauthor.au_id = @au_id)";
_ds.SelectParameters.Add(new Parameter("au_id", TypeCode.String, (string)_authorField.FieldValue));
}
else {
_ds.SelectParameters["au_id"].DefaultValue = (string)_authorField.FieldValue;
}
}
else {
_ds.SelectParameters.Clear();
_ds.SelectCommand = selectStatement;
}
_ds.DataBind();
base.OnPreRender(e);
}
}
}
VB.NET Code
Imports System
Imports System.Drawing
Imports System.ComponentModel
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Namespace MyWebParts
' <summary>
' WebPart to display the information of Authors
' </summary>
Public Class AuthorWebPart
Inherits WebPart
Implements IField
Private _view As GridView
Public Sub New()
MyBase.New()
End Sub
ReadOnly Property FieldValue() As Object _
Implements IField.FieldValue
Get
Return _view.SelectedValue
End Get
End Property
ReadOnly Property Schema() As PropertyDescriptor _
Implements IField.Schema
Get
Return TypeDescriptor.GetProperties(Me.GetType)("FieldValue")
End Get
End Property
Protected Overrides Sub CreateChildControls()
_view = New GridView
_view.ID = "_authorsGrid"
_view.AutoGenerateColumns = True
_view.DataKeyNames = New String() {"au_id"}
Dim field As CommandField = New CommandField
_view.SelectedRowStyle.BackColor = Color.Red
field.ShowSelectButton = True
_view.Columns.Add(field)
Dim ds As SqlDataSource = New SqlDataSource
ds.ID = "_authorsDS"
ds.ConnectionString = "server=carlosagmail;database=pubs;uid=sa;pwd=yourpassword"
ds.SelectCommand = "select au_id, au_lname, au_fname from authors"
_view.DataSourceID = ds.ID
Me.Controls.Add(ds)
Me.Controls.Add(_view)
End Sub
<ConnectionProvider("AuthorID")> _
Public Function GetAuthor() As IField
Return Me
End Function
End Class
' <summary>
' WebPart to display the information of Books
' </summary>
Public Class BooksWebPart
Inherits WebPart
Private _authorField As IField
Private _ds As SqlDataSource
<ConnectionConsumer("Author")> _
Public Sub SetAuthor(ByVal field As IField)
Me._authorField = field
End Sub
Protected Overrides Sub CreateChildControls()
Dim view As GridView = New GridView
view.ID = "_booksGrid"
view.AutoGenerateColumns = True
view.DataKeyNames = New String() {"title_id"}
Dim field As CommandField = New CommandField
view.SelectedRowStyle.BackColor = Color.Red
field.ShowSelectButton = True
view.Columns.Add(field)
_ds = New SqlDataSource
_ds.ID = "_booksDS"
_ds.ConnectionString = "server=carlosagmail;database=pubs;uid=sa;pwd=yourpassword"
view.DataSourceID = _ds.ID
Me.Controls.Add(_ds)
Me.Controls.Add(view)
End Sub
Protected Overrides Sub OnPreRender(ByVal e As EventArgs)
Dim selectStatement As String = "SELECT titles.title_id, titles.title, titles.type, titles.price, titles.pubdate FROM titles"
EnsureChildControls()
If (Not (_authorField) Is Nothing) Then
If (_ds.SelectParameters.Count = 0) Then
_ds.SelectCommand = (selectStatement + " INNER JOIN titleauthor ON titleauthor.title_id = titles.title_id WHERE (titleauthor.au_id = @au_id)")
_ds.SelectParameters.Add(New Parameter("au_id", TypeCode.String, CType(_authorField.FieldValue, String)))
Else
_ds.SelectParameters("au_id").DefaultValue = CType(_authorField.FieldValue, String)
End If
Else
_ds.SelectParameters.Clear()
_ds.SelectCommand = selectStatement
End If
_ds.DataBind()
MyBase.OnPreRender(e)
End Sub
End Class
End Namespace
The AuthorWebPart is a very straight forward composite control that has two child
controls a SqlDataSource and a GridView. The GridView exposes a Select link button
so users can select the author. This WebPart implements
System.Web.UI.WebControls.WebParts.IField
explicitly and exposes such interface using the ConnectionProvider attribute.
The BooksWebPart also defines a GridView and a SqlDataSource, however this webpart
verifies if the
IField information is available and if it is, it uses that
information to filter the books. If it is not available, then it displays all the
books. This way it is completely independent from any webpart.
Running the Sample
Browse to the page:
Browse to the Sample Page
The first time you run the page you will get a not very interesting empty page, just with the WebPartPage menu in Browse mode like the following image shows:
Set the page in CatalogDisplayMode:
Now, in the drop down menu select the option
"Add WebParts to this Page" and click Change
The page will show in Catalog DisplayMode so you can add new webparts to this page. In this case the only webparts that will be shown are the ones listed in the DeclarativeCatalogPart.
Add the WebParts
Now, Mark both Check Boxes and Click Add. You can see that you can add as many WebParts as you want.
Now you get a much more interesting page that allows you to minimize/restore/close parts of your page. It displays a list of all authors and a list of all books.
Creating the Connection
Now, lets link them together so you don't get all books but only the books for the selected author.
For this, select the option
"Connect Web Parts on this Page" and press Change
This will set the page in Connect Mode where you can establish connections between webparts. When you are on this mode you will get a small "black arrow" just at the left of the "Minimize" verb that you can click to see the
"Connect Verb"
Linking them together
Select the Connect verb in the Authors WebPart and scroll to the bottom of the page where the ConnectionZone will be visible.
Click the link
"Create a connection to a Consumer" and set the Books option in the drop down so both webparts get connected. Click Connect. And then Close the Connections Zone
Finally it works!!!
Now every time you select an Author in the Authors WebPart it will display only the books for the selected author instead of the whole list.
This sample, shows how you can use several features in WebParts to create very dynamic applications.