Evjen c17.tex V2 - 01/28/2008 2:58pm Page 847 Chapter 17: Portal Frameworks and Web Parts Controls.Add(InstructionText); Literal LineBreak = new Literal(); LineBreak.Text = " < br / > "; Controls.Add(LineBreak); Controls.Add(StateInput); Button InputButton = new Button(); InputButton.Text = "Input State"; InputButton.Click += this.Button1_Click; Controls.Add(InputButton); Literal Spacer = new Literal(); Spacer.Text = " < p > "; Controls.Add(Spacer); Controls.Add(StateContents); ChildControlsCreated = true; } private void Button1_Click(object sender, EventArgs e) { StateContents.Items.Add(StateInput.Text); StateInput.Text = String.Empty; StateInput.Focus(); } } } To review, you first import the System.Web.UI.WebControls.WebParts namespace. The important step in the creation of this custom control is to make sure that it inherits from the WebPart class instead of the customary Control class. As stated earlier, this gives the control access to the advanced functionality of the Portal Framework that a typical custom control would not have. VB Public Class StateListBox Inherits WebPart End Class C# public class StateListBox : WebPart { } After the class structure is in place, a few properties are defined, and the constructor is defined as well. The constructor directly uses some of the capabilities that the WebPart class provides. These capabilities would not be available if this custom control has the Control class as its base class and is making use of the WebPart.AllowClose property. 847 Evjen c17.tex V2 - 01/28/2008 2:58pm Page 848 Chapter 17: Portal Frameworks and Web Parts VB Public Sub New() Me.AllowClose = False End Sub C# public StateListBox() { AllowClose = false; } This constructor creates a control that explicitly sets the control’s AllowClose property to False —mean- ing that the Web Part will not have a Close link associated with it when generated in the page. Because of the use of the WebPart class instead of the Control class, you will find, in addition to the Allow- Close property, other WebPart class properties such as AllowEdit , AllowHide , AllowMinimize , Allow- ZoneChange ,andmore. In the example shown in Listing 17-14, you see a custom-defined property: LabelStartText .Thisprop- erty allows the developer to change the instruction text displayed at the top of the control. The big difference with this custom property is that it is preceded by the Personalizable and the WebBrowsable attributes. The Personalizable attribute enables the property for personalization, whereas the WebBrowsable attribute specifies whether the property should be displayed in the Properties window in Visual Stu- dio. The Personalizable attribute can be defined further using a PersonalizationScope enumeration. The only two possible enumerations — Shared and User — can be defined in the following ways: VB < Personalizable(PersonalizationScope.Shared), WebBrowsable() > _ Public Property LabelStartText() As String Get Return _LabelStartText End Get Set(ByVal value As String) _LabelStartText = value End Set End Property C# [Personalizable(PersonalizationScope.Shared), WebBrowsable] public String LabelStartText { get { return _LabelStartText; } set { _LabelStartText = value; } } A PersonalizationScope of User means that any modifications are done on a per-user basis. This is the default setting and means that if a user makes modifications to the property, the changes are seen only by that particular user and not by the other users that browse the page. If the PersonalizationScope is set to Shared , changes made by one user can be viewed by others requesting the page. 848 Evjen c17.tex V2 - 01/28/2008 2:58pm Page 849 Chapter 17: Portal Frameworks and Web Parts After you have any properties in place, the next step is to define what gets rendered to the page by over- riding the CreateChildControls method. From the example in Listing 17-14, the CreateChildControls method renders Label, Literal, TextBox, Button, and ListBox controls. In addition to defining the proper- ties of some of these controls, a single event is associated with the Button control ( Button1_Click )thatis also defined in this class. Now that the custom Web Part control is in place, build the project so that a DLL is created. The next step is to open up the ASP.NET Web project where you want to utilize this new control and, from the Visual Studio Toolbox, add the new control. You can quickly accomplish this task by right-clicking in the Toolbox on the tab where you want the new control to be placed. After right-clicking the appropriate tab, select Choose Items. Click the Browse button and point to the new MyStateListBox.dll that you just created. After this is done, the StateListBox control is highlighted and checked in the Choose Toolbox Items dialog, as illustrated in Figure 17-22. Figure 17-22 Clicking OK adds the control to your Toolbox. Now you are ready to use this new control as a Web Part control. To do this, simply drag and drop the control into one of your Web Part Zone areas. This does a couple of things. First, it registers the control on the page using the Register directive: < %@ Register TagPrefix="cc1" Namespace="MyStateListBox.Wrox" Assembly="MyStateListBox" % > 849 Evjen c17.tex V2 - 01/28/2008 2:58pm Page 850 Chapter 17: Portal Frameworks and Web Parts Once registered, the control can be used on the page. If dragged and dropped onto the page’s design surface, you get a control in the following construct: < cc1:StateListBox Runat="server" ID="StateListBox1" LabelStartText=" Enter State Name: " AllowClose="False" / > The two important things to notice with this construct is that the custom property, LabelStartText ,is present and has the default value in place, and the AllowClose attribute is included. The AllowClose attribute is present only because earlier you made the control’s inherited class WebPart and not Control . Because WebPart was made the inherited class, you have access to these Web Part–specific properties. When the StateListBox control is drawn on the page, you can see that, indeed, it is part of the larger Portal Framework and allows for things such as minimization and editing. End users can use this custom Web Part control as if it were any other type of Web Part control. As you can see, you have a lot of power when you create your own Web Part controls. And because LabelStartText uses the WebBrowsable attribute, you can use the PropertyGridEditorPart control to allow end users to edit this directly in the browser. With this in place, as was demonstrated earlier in Listing 17-5, an end user will see the following editing capabilities after switching to the Edit mode (see Figure 17-23). Figure 17-23 Connecting Web Parts In working with Web Parts, you sometimes need to connect them in some fashion. Connecting them means that you must pass a piece of information (an object) from one Web Part to another Web Part on the page. For instance, you might want to transfer the text value (such as a zip code or a name) that someone enters in a text box to other Web Parts in the page. Another example is a DropDownList control that specifies all the available currencies in the system. If the end user selects from the drop-down list, this drives changes in all the other Web Parts on that page that deal with this currency value selection. When you need to build constructions in this manner, you can use the Web Part connection capabilities defined here, or you might be able to work with other ASP.NET systems available (such as the personalization capabilities provided through the profile system). When connecting Web Parts, you should be aware of the specific rules on how these Web Parts interact with one another. First off, if you want to make a connection from one Web Part to another, one of theWebPartsmustbetheprovider. This provider Web Part is the component that supplies the piece of information required by any other Web Parts. The Web Parts that require this information are the consumer Web Parts. A Web Part provider can supply information to one or more consumer Web Parts; however, a consumer Web Part can only connect with a single provider Web Part. You cannot have a consumer Web Part that connects to more than one provider Web Part. 850 Evjen c17.tex V2 - 01/28/2008 2:58pm Page 851 Chapter 17: Portal Frameworks and Web Parts An example of this scenario is illustrated in Figure 17-24. WEB PAGE WEB PART ZONE 1 WEB PART ZONE 2 PROVIDER WEB PART PROVIDER WEB PART CONSUMER WEB PART CONSUMER WEB PART Figure 17-24 From this diagram, you can see that it is possible to use a single provider Web Part with multiple con- sumer Web Parts regardless of the Web Part Zone area in which the consumer Web Part resides. When working with provider and consumer Web Parts, be aware that no matter how simple or com- plicated the Web Part is, you must wrap the Web Part by making it a custom Web Part. You do this to expose the correct item or property from the provider Web Part or to utilize the passed value in the correct manner for the consumer Web Part. This chapter reviews a simple example of connecting Web Parts. Although many steps are required to accomplish this task, you definitely get a lot of value from it as well. Building the Provider Web Part In order to build a provider Web Part that can be utilized by any consumer Web Part residing on the page, you first create an interface exposing the item you want to pass from one Web Part to another. For this example, suppose you want to provide a text box as a Web Part that allows the end user to input a value. This value is then utilized by a calendar control contained within a Web Part in an entirely different Web Part Zone on the page using the Calendar control’s Caption property. This interface is demonstrated in Listing 17-15. Listing 17-15: Building an interface to expose the property used to pass to a Web Part VB Namespace Wrox.ConnectionManagement Public Interface IStringForCalendar Property CalendarString() As String End Interface End Namespace Continued 851 Evjen c17.tex V2 - 01/28/2008 2:58pm Page 852 Chapter 17: Portal Frameworks and Web Parts C# namespace Wrox.ConnectionManagement { public interface IStringForCalendar { string CalendarString { get; set;} } } From this bit of code, you can see that the interface, IStringForCalendar ,isquitesimple.Itexposesonly a single String property — CalendarString . This interface is then utilized by the custom provider Web Part shown next. The custom provider Web Part is built like any other custom Web Part in the manner demonstrated earlier in this chapter. The only difference is that you also provide some extra details so ASP.NET knows what item you are exposing from the Web Part and how this value is retrieved. This custom provider Web Part is illustrated in Listing 17-16. Listing 17-16: Building a custom provider Web Part VB Imports Microsoft.VisualBasic Imports System.Web.UI.WebControls Imports System.Web.UI.WebControls.WebParts Namespace Wrox.ConnectionManagement Public Class TextBoxChanger Inherits WebPart Implements IStringForCalendar Private myTextBox As TextBox Private _calendarString As String = String.Empty < Personalizable() > _ Public Property CalendarString() As String Implements _ Wrox.ConnectionManagement.IStringForCalendar.CalendarString Get Return _calendarString End Get Set(ByVal value As String) _calendarString = value End Set End Property < ConnectionProvider("Provider for String From TextBox", _ "TextBoxStringProvider") > _ Public Function TextBoxStringProvider() As IStringForCalendar Return Me End Function Continued 852 Evjen c17.tex V2 - 01/28/2008 2:58pm Page 853 Chapter 17: Portal Frameworks and Web Parts Protected Overrides Sub CreateChildControls() Controls.Clear() myTextBox = New TextBox() Me.Controls.Add(myTextBox) Dim myButton As Button = New Button() myButton.Text = "Change Calendar Caption" AddHandler myButton.Click, AddressOf Me.myButton_Click Me.Controls.Add(myButton) End Sub Private Sub myButton_Click(ByVal sender As Object, ByVal e As EventArgs) If myTextBox.Text <> String.Empty Then CalendarString = myTextBox.Text myTextBox.Text = String.Empty End If End Sub End Class End Namespace C# using System; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; namespace Wrox.ConnectionManagement { public class TextBoxChanger : WebPart, IStringForCalendar { private TextBox myTextBox; private string _calendarString = String.Empty; [Personalizable] public string CalendarString { get { return _calendarString; } set { _calendarString = value; } } [ConnectionProvider("Provider for String From TextBox", "TextBoxStringProvider")] public IStringForCalendar TextBoxStringProvider() { return this; } protected override void CreateChildControls() { Controls.Clear(); myTextBox = new TextBox(); Controls.Add(myTextBox); Button myButton = new Button(); myButton.Text = "Change Calendar Caption"; myButton.Click += this.myButton_Click; Continued 853 Evjen c17.tex V2 - 01/28/2008 2:58pm Page 854 Chapter 17: Portal Frameworks and Web Parts Controls.Add(myButton); } private void myButton_Click(object sender, EventArgs e) { if (myTextBox.Text != String.Empty) { CalendarString = myTextBox.Text; myTextBox.Text = String.Empty; } } } } Not only does this Web Part inherit the WebPart class, this provider Web Part implements the interface, IStringForCalendar , which was created earlier in Listing 17-15. From IStringForCalendar , the single String property is utilized and given the Personalizable() attribute. The important bit from the code presented in Listing 17-16 is the TextBoxStringProvider() method. This method returns a type of IStringForCalendar andisdefinedevenfurtherusingthe ConnectionProvider attribute. This attribute enables you to give a friendly name to the provider as well a programmatic name that can be used within the consumer custom Web Part that will be built shortly. Using the CreateChildControls() method, you layout the design of the Web Part. In this case, a text box and button are the only controls that make up this Web Part. In addition to simply laying out the controls on the design surface, you use this method to assign any specific control events — such as a button-click event by assigning handlers to the controls that require them. Finally, from within the button-click event of this Web Part ( myButton_Click ), the exposed property of IStringForCalendar is assigned a value. Everything is now in place for a consumer Web Part. The construction of this second Web Part is demonstrated next. Building the Consumer Web Part After you have a provider Web Part in place on your page, you can utilize the object it supplies for any number of consumer Web Parts on the same page. In this example, however, you are interested in using the String value coming from the TextBox control in the provider Web Part. The consumer Web Part takes this String and assigns it as the value of the Calendar control’s Caption property. The construction of the consumer Web Part is illustrated in Listing 17-17. Listing 17-17: The consumer Web Part VB Imports Microsoft.VisualBasic Imports System.Web.UI.WebControls Imports System.Web.UI.WebControls.WebParts Namespace Wrox.ConnectionManagement Public Class ModifyableCalendar Inherits WebPart Continued 854 Evjen c17.tex V2 - 01/28/2008 2:58pm Page 855 Chapter 17: Portal Frameworks and Web Parts Private _myProvider As IStringForCalendar Private _stringTitle As String Private myCalendar As Calendar = New Calendar() < ConnectionConsumer("Calendar Title Consumer", "CalendarTitleConsumer") > _ Public Sub RetrieveTitle(ByVal Provider As IStringForCalendar) _myProvider = Provider End Sub Protected Overrides Sub OnPreRender(ByVal e As EventArgs) EnsureChildControls() If Not (Me._myProvider Is Nothing) Then _stringTitle = _myProvider.CalendarString.Trim() myCalendar.Caption = _stringTitle End If End Sub Protected Overrides Sub CreateChildControls() Controls.Clear() Me.Controls.Add(myCalendar) End Sub End Class End Namespace C# using System; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; namespace Wrox.ConnectionManagement { public class ModifyableCalendar : WebPart { private IStringForCalendar _myProvider; string _stringTitle; Calendar myCalendar; [ConnectionConsumer("Calendar Title Consumer", "CalendarTitleConsumer")] public void RetrieveTitle(IStringForCalendar Provider) { _myProvider = Provider; } protected override void OnPreRender(EventArgs e) { EnsureChildControls(); if (_myProvider != null) { _stringTitle = _myProvider.CalendarString.Trim(); myCalendar.Caption = _stringTitle; } Continued 855 Evjen c17.tex V2 - 01/28/2008 2:58pm Page 856 Chapter 17: Portal Frameworks and Web Parts } protected override void CreateChildControls() { Controls.Clear(); myCalendar = new Calendar(); Controls.Add(myCalendar); } } } This new custom Web Part, ModifyableCalendar , is simply a class that inherits from WebPart and noth- ing more. It requires a reference to the interface IStringForCalendar .Because IStringForCalendar is part of the same namespace, you can provide a simple reference to this interface. Your consumer Web Part requires a method that is the connection point for a provider Web Part on the same page. In this case, the RetrieveTitle() method is constructed using the ConnectionConsumer attribute before the method declaration. Like the ConnectionProvider attribute that was utilized in the provider Web Part, the ConnectionConsumer Web Part enables you to give your Web Part a friendly name and a reference name to use programmatically. Then, the value retrieved from the provider Web Part is grabbed from within the PreRender() method of the Web Part and assigned to the Calendar control before the actual Calendar control is placed on the page from within the CreateChildControls() method. Now that both a provider and a consumer Web Part are available to you, the next step is to get them both on an ASP.NET page and build the mechanics to tie the two Web Parts together. This is demonstrated next. Connecting Web Parts on an ASP.NET Page When in the process of connecting Web Parts, remember that you need a provider Web Part and a con- sumer Web Part. These items are detailed in Listings 17-16 and 17-17, respectively. When working with the process of connecting Web Parts, it is not simply a matter of placing both of these items on the page to get the connections to take place. In addition to this step, you have to wire the Web Parts together. This wiring of Web Part connections is done through the WebPartManager control that is discussed at the beginning part of this chapter. The ASP.NET page used for this example is detailed in Listing 17-18. Listing 17-18: The ASP.NET page that connects two Web Part controls < %@ Page Language="VB" % > < %@ Register Namespace="Wrox.ConnectionManagement" TagPrefix="connectionControls" % > < html xmlns="http://www.w3.org/1999/xhtml" > < head runat="server" > < title > Connecting Web Parts < /title > < /head > < body > Continued 856 . demonstrated earlier in Listing 17 -5, an end user will see the following editing capabilities after switching to the Edit mode (see Figure 17- 23) . Figure 17- 23 Connecting Web Parts In working with Web Parts,. ModifyableCalendar Inherits WebPart Continued 854 Evjen c17.tex V2 - 01/28/2008 2 :58 pm Page 855 Chapter 17: Portal Frameworks and Web Parts Private _myProvider As IStringForCalendar Private _stringTitle As String Private. demonstrated next. Connecting Web Parts on an ASP. NET Page When in the process of connecting Web Parts, remember that you need a provider Web Part and a con- sumer Web Part. These items are detailed in Listings 17-16